Introduction

In the first assignment, we utilized the RNASeq data from Sanghi et al.’s publication “Chromatin Accessibility Associates with Protein-RNA Correlation in Human Cancer”(Sanghi, Gruber, and Metwally (2021)) to perform data cleaning, normalization, gene mapping to HUGO symbols, and preliminary analysis. The goal of the original study was to explore the relationship between chromatin structure alterations and molecular phenotypes in cancer by utilizing multi-omics profiling of human tumors. They applied this approach to a total of 36 individuals to obtain thyroid cancer primary tumors, metastases, and patient-matched normal tissue, with a total of 87 samples. The study identified a local chromatin structure that is highly correlated with coordinated RNA and protein expression, particularly within gene-body enhancers, and claimed that local enhancers may be more important for regulating cancer gene expression than distal enhancers. Moreover, the authors found that TFs in the MAPK pathway are actively bound significantly more in tumor and metastases than in normal tissue.

We obtained the dataset with the ID GSE162515 from GEO, which is linked to the study “Chromatin Accessibility Associates with Protein-RNA Correlation in Human Cancer”. The dataset contains a total of 28,883 genes, and the experiment conditions are categorized into 27 normal tissue samples, 30 tumor tissue samples, and 30 metastases tissue samples.

To improve the data quality, we removed genes with less than 1 count per million (cpm) in less than three samples, resulting in the removal of 11,538 genes. We then performed normalization using TMM with the edgeR package to correct the large deviation of means between the tumor, metastases and normal tissue groups while still preserving some of the original sample distribution. Interestingly, the data was already well-aligned after removing low counts, so the normalization step barely improved the quality of the dataset. Figures such as MDS plot and BCV plot are generated to visualize the quality, as shown below.

From the post-normalization MDS plot, we observed that the overall separation between each test condition group (T and M) and the normal group is clear, indicating a good dataset quality.

Additionally, the variance of the data was relatively consistent with the expected trend, as indicated by the dispersion-squared BCV plot.

To map identifiers, we utilized the package biomaRt. Fortunately, gene IDs in the original dataset were mostly already mapped to the corresponding HUGO gene symbols. After removing low counts, genes with duplicate identifiers, and genes that cannot be mapped to HUGO symbols, the final dataset contained 17,368 unique genes.

Download Packages

In this section, we import and install the necessary packages for this assignment, in which we will conduct a differential expression analysis using the normalized dataset and a thresholded over-representation analysis.

if (!requireNamespace("BiocManager", quietly = TRUE)){
  install.packages("BiocManager")}

if (!requireNamespace("GEOmetadb", quietly = TRUE)){
  BiocManager::install("GEOmetadb")}

if (!requireNamespace("circlize", quietly = TRUE))
    install.packages("circlize")

if (!requireNamespace("ComplexHeatmap", quietly = TRUE))
    BiocManager::install("ComplexHeatmap")
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
if (!requireNamespace("gprofiler2", quietly = TRUE))
    BiocManager::install("gprofiler2")

if (!requireNamespace("ggplot2", quietly = TRUE)){
  install.packages("ggplot2")}

if (!requireNamespace("edgeR", quietly = TRUE)){
  BiocManager::install("edgeR")}

if (!requireNamespace("biomaRt", quietly = TRUE)){
  BiocManager::install("biomaRt")}

if (!requireNamespace("knitr", quietly = TRUE)){
  install.packages("knitr")}

if (!requireNamespace("GEOquery", quietly = TRUE)){
  BiocManager::install("GEOquery")}

if (!requireNamespace("Biobase", quietly = TRUE)){
  BiocManager::install("Biobase")}

if (!requireNamespace("dplyr", quietly = TRUE)){
  install.packages("dplyr")}

if (!requireNamespace("kableExtra", quietly = TRUE)){
  install.packages("kableExtra")}

Load packages

library("GEOmetadb")
library("ggplot2")
library("edgeR")
library("biomaRt")
library("ComplexHeatmap")
library("circlize")
library("dplyr")
library("GEOquery")
library("Biobase")
library("knitr")
library("kableExtra")

Differential Expression Analysis

In this section, we will use edgeR package to perform differential expression analysis.

Retrieve information from Assignment 1

The normalized data processed from Assignment 1 has been stored in the file named as “normalized_counts_final.txt”. We now load this data into R. The categories for the samples were saved in “samples.txt” file. We can also load it into R.

normalized_counts <- read.table("normalized_counts_final.txt")
samples <- read.table("samples.txt")

Examine the normalized dataset

The format of the normalized count dataset has already been processed in a way that can be directly used to plot the heatmap, which would be our next step.

kable(normalized_counts[1:5,1:5], format = "html")
F001.C1.T F002.C1.N F003.C1.M F004.C2.T F005.C2.N
A1BG-AS1 9.941028 4.706365 11.072142 5.9720957 3.615496
A2M 639.332343 806.127267 728.618408 565.2189214 515.208115
A2M-AS1 0.379692 2.312610 1.428664 0.6846989 2.824606
A4GALT 6.282177 14.200239 16.310575 11.2214538 9.151723
AAAS 29.512426 30.713088 28.751854 34.8055261 24.178626

Examine the samples information

There are two columns, “individuals” and “tissue type”. The “individual” column stores data of the patients who the authors took the samples from, and the “tissue type” indicates the type of the tissue, including tumors, metastases, and normal tissue.

knitr::kable(head(samples, 10),  format = "html")
individual tissue_type
F001.C1.T C1 T
F002.C1.N C1 N
F003.C1.M C1 M
F004.C2.T C2 T
F005.C2.N C2 N
F007.C3.T C3 T
F009.C4.T C4 T
F010.C4.N C4 N
F014.C5.N C5 N
F017.C7.T C7 T

Design Model

In this section, we will create a data matrix from our dataset.

In order to perform statistical testing, we need a design matrix that defines our model. Notice that in our dataset, there are two factors:

  1. Tissue types (Normal, tumor, metastases)
  2. Patient (individual)

Hence, ideally, we would like to account for both factors in our design matrix.

Recall that we want to find the genes that are differentially expressed in the tumor and metastases samples in contrast to normal tissues, so we first factor the tissue types such that “N” type becomes the baseline/reference level. This would affect on which tissue type would be chosen as the control value (i.e. intercept) when performing model.matrix function to generate the design matrix.

# Set normal tissue type as the intercept
samples$tissue_type <- factor(samples$tissue_type)
samples$tissue_type <- relevel(samples$tissue_type, ref="N")

# Doesn't really matter for individual people, but we can set C1 as the intercept for the sake of tidiness.
samples$individual <- factor(samples$individual)
samples$individual <- relevel(samples$individual, ref="C1")

# Generate design matrix
model_design <- model.matrix(~ samples$individual + samples$tissue_type)

model_design[1:5,1:5]
  (Intercept) samples$individualC10 samples$individualC11 samples$individualC12 samples$individualC13
1           1                     0                     0                     0                     0
2           1                     0                     0                     0                     0
3           1                     0                     0                     0                     0
4           1                     0                     0                     0                     0
5           1                     0                     0                     0                     0

Analysis Using edgeR

For our downstream analysis, we are going to use edgeR, which is specifically designed for RNASeq data. First, we create the base edgeR object called DGEList. The group we want to define is the tissue type.

d <- edgeR::DGEList(counts = normalized_counts, group = samples$tissue_type)

For further processing, we choose to use the quasi-likelihood models since our dataset is from an RNASeq experiment and quasi-likelihood models are best suited to handle RNASeq data.

Check Eligibility

One important underlying assumption for using the Quasi-likelihood model is that the data follows a negative binomial distribution. We need to verify that our dataset indeed meets that assumption.

To do this, we calculate the dispersion and generate the plot to visualize the mean-variance relationship.

d <- edgeR::estimateDisp(d, model_design)
# Generate MV plot
edgeR::plotMeanVar(d,
                   show.raw.vars = TRUE,
                   show.tagwise.vars = TRUE,
                   NBline = TRUE,
                   show.ave.raw.vars = TRUE,
                   show.binned.common.disp.vars = TRUE,
                   main = "Mean-Variance Plot for Normalized Data")
# Display legend
legend("topleft", 
       legend=c("Raw Data", "Tagwise Dispersion", "Average Raw Variances", 
                "Binned Common Dispersion", "Negative Binomial Line"), 
       col = c("grey", "lightblue", "maroon", "red", "dodgerblue2"), pch=c(1,1,4,4,NA), lty=c(0,0,0,0,1), lwd=c(1,1,1,1,2), cex=0.6)

From the MV plot, we can see that our normalized count data follows the negative binomial distribution, where it clearly aligns with the blue line indicating the negative binomial trend.


Now, we have created the design matrix and verified the assumption for the data to be negative-binomially distributed, we can proceed to the next stage of our analysis. We fit the model using our design matrix:

fit <- edgeR::glmQLFit(d, model_design)


Once we have fit the model, we can proceed to calculate differential expression. We will perform the calculation separately for Tumor vs. Normal, and Metastases vs. Normal. To ensure that the significantly differentially expressed genes are not obtained by random, we will perform correction for multiple hypothesis testing using Benjamini-Hochberg approach.

Tumor vs. Normal

In this section, we want to test for differential expression between the tumor samples and normal samples.

qlf_tn <- edgeR::glmQLFTest(fit, coef='samples$tissue_typeT')

qlf_tn_hits <- edgeR::topTags(qlf_tn,sort.by = "PValue", adjust.method = "BH",
                           n = nrow(normalized_counts))
knitr::kable(head(qlf_tn_hits$table), format = "html")
logFC logCPM F PValue FDR
CLDN16 5.384950 5.772560 122.90420 0 0
LHX2 3.473253 1.701027 130.64741 0 0
HS6ST2 4.133289 4.429133 110.57323 0 0
PRR15 5.114034 5.685377 107.41459 0 0
SLIT1 4.810897 5.765108 100.52563 0 0
ABCC11 3.961639 2.420472 99.50698 0 0
NA


We can examine the number of genes pass the threshold and correction. We are using 0.05 as the threshold for p-value as it is commonly used in practice.

Number of genes that passed the threshold:

length(which(qlf_tn_hits$table$PValue < 0.05))
[1] 7145


Number of genes that passed correction:

length(which(qlf_tn_hits$table$FDR < 0.05))
[1] 5648


The threshold of 0.05 gives us quite a lot of genes. However, since we are dealing with human disease, which should be more strict to obtain more meaningful hits for further analysis, we choose to use a more stringent threshold of 0.01.

Number of genes that passed the 0.01 p value threshold:

length(which(qlf_tn_hits$table$PValue < 0.01))
[1] 5156


Number of genes that passed correction of 0.01 threshold:

length(which(qlf_tn_hits$table$FDR < 0.01))
[1] 3893


There are still a lot of genes left for further analysis. In later sections, genes that have differentially expressed for less than 2 log fold change (LFC) would also be filtered out to obtain a set of more meaningful data.

Metastases vs. Normal

In this section, we test for differential expression between the metastasis tissues and the normal tissues.

qlf_mn <- edgeR::glmQLFTest(fit, coef='samples$tissue_typeM')
qlf_mn_hits <- edgeR::topTags(qlf_mn,sort.by = "PValue", adjust.method = "BH",
                           n = nrow(normalized_counts))
knitr::kable(head(qlf_mn_hits$table), format = "html")
logFC logCPM F PValue FDR
CDH16 -6.791713 5.728732 195.1855 0 0
CWH43 -4.967247 3.916405 187.8185 0 0
CHGA -4.588762 1.320610 647.5490 0 0
CLCNKB -3.512404 3.970571 170.1807 0 0
CCDC146 -2.524562 4.409113 161.5505 0 0
APOA1 -4.051688 2.087150 160.0036 0 0
NA


We apply the 0.01 threshold for the same reason as indicated previously.

Number of genes that passed the 0.01 p value threshold:

length(which(qlf_mn_hits$table$PValue < 0.01))
[1] 6590


Number of genes that passed correction with 0.01 threshold:

length(which(qlf_mn_hits$table$FDR < 0.01))
[1] 5477


Again, we would also filter out the genes that have differentially expressed less than 2 LFC in later sections.

Volcano Plot (Tumor vs. Normal)

We plot the volcano plot to visualize differential expression of genes for tumor vs. normal tissue samples. Each gene is represented by a point in the plot. The horizontal axis of the plot is the log2 fold change and the vertical axis is the -log10p which indicates how likely the differential of a gene is due to actual biological variation.

# Make all data to grey first
volcano_color_tn = rep('gray', times = nrow(qlf_tn_hits$table))

# For those down-regulated genes with more than 2 LFC and passes 0.01 FDR 
# correction threshold, make it blue
volcano_color_tn[qlf_tn_hits$table$logFC < 0 &
                        qlf_tn_hits$table$FDR < 0.01
                      & abs(qlf_tn_hits$table$logFC) > 2] <- 'blue'

# For up-regulated genes with more than 2LFC and passes 0.01 FDR
# correction threshold, make it red
volcano_color_tn[qlf_tn_hits$table$logFC > 0 &
                        qlf_tn_hits$table$FDR < 0.01 &
                        abs(qlf_tn_hits$table$logFC) > 2] <- 'red'

# Plot the volcano plot
plot(qlf_tn_hits$table$logFC,
     -log(qlf_tn_hits$table$PValue, base=10),
     col = volcano_color_tn,
     xlab = "log2 fold change",
     ylab = "-log10 p",
     main = "Volcano plot for Tumor vs. Normal Tissues"
)

# Add the legend
legend("topleft", legend=c("Downregulated in tumor tissues","Upregulated in tumor tissues", "Not significant"),
       fill = c("blue", "red", "grey"), cex = 0.5)

# Label genes with over 4 LFC
tn_sig <- which(qlf_tn_hits$table$logFC > 5 | qlf_tn_hits$table$logFC < -4)
text(x = qlf_tn_hits$table$logFC[tn_sig] , y = -log10(qlf_tn_hits$table$PValue[tn_sig]),
     label = rownames(qlf_tn_hits$table)[tn_sig], cex = 0.5, adj = c(1, NA), pos = 3)


There is extensive number of upregulated genes in tumor tissues compared to normal tissues, with the highest of exceeding 6 LFC (log2 Fold Change). Several genes are significantly downregulated, having more than 4 LFC.


Volcano Plot (Metastases vs. Normal)

We also plot the volcano plot to visualize differential expression of genes for metastases vs. normal tissue samples.

# Make all data to grey first
volcano_color_mn = rep('gray', times = nrow(qlf_mn_hits$table))

# For those down-regulated genes with more than 2 LFC and passes 0.01 FDR 
# correction threshold, make it blue
volcano_color_mn[qlf_mn_hits$table$logFC < 0 &
                        qlf_mn_hits$table$FDR < 0.01
                      & abs(qlf_mn_hits$table$logFC) > 2] <- 'blue'

# For up-regulated genes with more than 2LFC and passes 0.01 FDR
# correction threshold, make it red
volcano_color_mn[qlf_mn_hits$table$logFC > 0 &
                        qlf_mn_hits$table$FDR < 0.01 &
                        abs(qlf_mn_hits$table$logFC) > 2] <- 'red'

# Plot the volcano plot
plot(qlf_mn_hits$table$logFC,
     -log(qlf_mn_hits$table$PValue, base=10),
     col = volcano_color_mn,
     xlab = "log2 fold change",
     ylab = "-log10 p",
     main = "Volcano plot for Metastases vs. Normal Tissues"
    )


# Add the legend
legend("topright", legend=c("Downregulated in tumor tissues","Upregulated in tumor tissues", "Not significant"),fill = c("blue", "red", "grey"), cex = 0.5)

# Label genes with over 5 LFC
mn_sig <- which(qlf_mn_hits$table$logFC > 5 | qlf_mn_hits$table$logFC < -5)
text(x = qlf_mn_hits$table$logFC[mn_sig] , y = -log10(qlf_mn_hits$table$PValue[mn_sig]), label = rownames(qlf_mn_hits$table)[mn_sig], cex = 0.5, adj = c(1, NA), pos = 3)


There is extensive number of upregulated and downregulated genes in metastases tissues compared to normal tissues, with the highest of exceeding 5 LFC.


Heatmap (Tumor vs. Normal)

In order to find the most significantly differentially expressed, we pick the hits that pass a P-value threshold of 0.01, and has absolute value of LFC larger than 2 as the top hits.

# Get top hit genes for T vs N
top_hits_tn <- rownames(qlf_tn_hits)[qlf_tn_hits$table$PValue < 0.01 & abs(qlf_tn_hits$table$logFC) > 2]

Then, we calculate their log2 counts per million value. We add 1 to the value to eliminate mathematical error when the count is 0. This technique is commonly used in practise when calculating log values.

# Calculate logCPM
hm_matrix <- log2(normalized_counts + 1) # Plus 1 to eliminate error when the count is 0.

Obtain data for each category

# Obtain tumor and normal tissue samples
tumor <- grep("T$", colnames(hm_matrix), value=TRUE)
normal <- grep("N$", colnames(hm_matrix), value=TRUE)
metastases <- grep("M$", colnames(hm_matrix), value=TRUE)

Scale heat map matrix by rows.

# Scale heat map matrix by rows
hm_matrix_tn <- t(scale(t(hm_matrix[rownames(hm_matrix) %in% top_hits_tn, c(tumor, normal)])))

Pick the color to be used for the plot. If heatmap only contains non-negative values, we will use only white and red, where white indicates 0, and red indicates positive values.

Otherwise, we will use blue to represent negative values.

We plot the heatmap to visualize differential expression of genes for metastases vs. normal tissue samples.

# Choose colors to be used
if(min(hm_matrix_tn) == 0){
    heatmap_color = colorRamp2(c( 0, max(hm_matrix_tn)),
                             c( "white", "red"))
  } else {
    heatmap_color = colorRamp2(c(min(hm_matrix_tn), 0,
          max(hm_matrix_tn)), c("blue", "white", "red"))
  }

# Create the heatmap from the given matrix, showing the dendrogram for both genes and samples.
name = "Expression level"
hm_tn <- Heatmap(as.matrix(hm_matrix_tn),
      show_row_dend = TRUE, show_column_dend = TRUE,
      col = heatmap_color, show_column_names = TRUE,
      show_row_names = FALSE, show_heatmap_legend = TRUE,
      column_names_gp = grid::gpar(fontsize = 6),
      heatmap_legend_param = list(title = name))

draw(hm_tn,
   column_title="Tumor vs. Normal Tissue Heatmap for Top DE Genes",
   column_title_gp=grid::gpar(fontsize=12))

Heatmap (Metastases vs. Normal)

Now we can also plot heatmap for Metastases vs. Normal comparison, with same steps as above.

# Get top hit genes for M vs N
top_hits_mn <- rownames(qlf_mn_hits)[qlf_mn_hits$table$PValue < 0.01 & abs(qlf_mn_hits$table$logFC) > 2]
# Scale heat map matrix by rows
hm_matrix_mn <- t(scale(t(hm_matrix[rownames(hm_matrix) %in% top_hits_mn, c(metastases, normal)])))
# Choose colors to be used
if(min(hm_matrix_mn) == 0){
    heatmap_color = colorRamp2(c( 0, max(hm_matrix_mn)),
                             c( "white", "red"))
  } else {
    heatmap_color = colorRamp2(c(min(hm_matrix_mn), 0,
          max(hm_matrix_mn)), c("blue", "white", "red"))
  }

# Create the heatmap from the given matrix, showing the dendrogram for both genes and samples.
hm_mn <- Heatmap(as.matrix(hm_matrix_mn),
      show_row_dend = TRUE, show_column_dend = TRUE,
      col = heatmap_color, show_column_names = TRUE,
      show_row_names = FALSE, show_heatmap_legend = TRUE,
      column_names_gp = grid::gpar(fontsize = 6),
      heatmap_legend_param = list(title = name))

draw(hm_mn,
   column_title="Metastases vs Normal Tissue Heatmap for Top DE Genes",
   column_title_gp=grid::gpar(fontsize=12))

Differential Expression Analysis Discussion

1. Calculate p-values for each of the genes in your expression set. How many genes were significantly differentially expressed? What thresholds did you use and why?

At first, I employed the commonly used p-value of 0.05, resulting in 7145 genes for the tumor vs. normal tissue analysis, and 8634 genes for the metastases vs. normal tissue analysis, before multiple hypothesis testing corrections. However, this was an extensive set of genes, prompting us to alter the p-value threshold to 0.01, and FDR threshold also to 0.01, to restrict the number of genes to be included. Additionally, we imposed a criterion that a gene should have an absolute log2 fold change of at least 2. This ensured that we only obtained genes with significant differential expression, which we believed to be meaningful and essential for further analysis.

2. Multiple hypothesis testing - correct your p-values using a multiple hypothesis correction method. Which method did you use? And Why? How many genes passed correction?

The two primary approaches for controlling false discovery rate are Bonferroni and Benjamini-Hochberg corrections, and we employed the Benjamini-Hochberg method for multiple hypothesis testing correction. Our objective was to identify significant hits without omitting meaningful ones. Bonferroni method is useful when the number of tests is small and when the tests are independent of each other, but it becomes overly stringent and impractical when the number of tests is large or when the tests are correlated. Since we are dealing with a large dataset with over 80 samples, Bonferroni is not desirable for our purpose. Therefore, we opted for Benjamini-Hochberg correction, which provided a more comprehensive set of genes for downstream analysis. Following this correction, we found that the tumor vs. normal tissue analysis yielded 3893 genes, and the metastases vs. normal tissue analysis yielded 5477 genes that passed the correction.

3. Show the amount of differentially expressed genes using an MA Plot or a Volcano plot. Highlight genes of interest.

Volcano plots for both Tumor vs. Normal and Metastases vs. Normal datasets are shown above. The most significantly differentially expressed genes are labeled out by their HUGO symbols in the figures.

4. Visualize your top hits using a heatmap. Do your conditions cluster together? Explain why or why not.

There are clear clusterings within conditions, as shown in the graph represented in red and blue. This suggests that the tumor tissues and metastases tissues do have genes that are highly differentially expressed compared to normal tissues.

Thresholded Overrepresentation Analysis using g:Profiler

For the final part of this assignment, we will perform a thresholded overrepresentation analysis using g:Profiler. In the previous section, we have compiled a list of differentially expressed genes. Here, we want to further divide them into upregulated and downregulated genes.

Tumor vs. Normal Tissue

First, we obtain the upregulated and downregulated genes from the tumor vs. normal tissue dataset.

upregulated_tn <- qlf_tn_hits[qlf_tn_hits$table$logFC > 0 & qlf_tn_hits$table$PValue < 0.01, ]
downregulated_tn <- qlf_tn_hits[qlf_tn_hits$table$logFC < 0 & qlf_tn_hits$table$PValue < 0.01, ]

We use the R package for g:Profiler to perform the gene enrichment analysis. For correction, we used FDR as it is less stringent than Bonferroni and is introduced to be the preferred correction method in class. We used GO Biological Process, GO Molecular Function, and WP as those are the ones used previously in Journal entry assignments, which we are more familiar with.

Then, we perform analysis separately for up-regulated genes and down-regulated genes.

Upregulated Genes

To obtain the terms these genes are involved in, we use the gost function from gProfiler2 package.

tn_up_top_terms_all <- gprofiler2::gost(query = rownames(upregulated_tn), 
                                  organism = "hsapiens", 
                                  exclude_iea = TRUE,
                                  correction_method = "fdr",
                                  sources = c("GO:BP", "REAC", "WP"))

tn_up_top_terms <- data.frame(
  term_name = tn_up_top_terms_all$result$term_name[tn_up_top_terms_all$result$term_size < 500 &
                                               tn_up_top_terms_all$result$term_size > 1],
  term_id = tn_up_top_terms_all$result$term_id[tn_up_top_terms_all$result$term_size < 500 &
                                           tn_up_top_terms_all$result$term_size > 1],
  source = tn_up_top_terms_all$result$source[tn_up_top_terms_all$result$term_size < 500 &
                                         tn_up_top_terms_all$result$term_size > 1]
)

knitr::kable(head(tn_up_top_terms, 10), format = "html")
term_name term_id source
external encapsulating structure organization GO:0045229 GO:BP
extracellular matrix organization GO:0030198 GO:BP
extracellular structure organization GO:0043062 GO:BP
cell projection morphogenesis GO:0048858 GO:BP
cell part morphogenesis GO:0032990 GO:BP
plasma membrane bounded cell projection morphogenesis GO:0120039 GO:BP
response to wounding GO:0009611 GO:BP
neuron projection morphogenesis GO:0048812 GO:BP
cell junction assembly GO:0034329 GO:BP
chemotaxis GO:0006935 GO:BP

For context, let’s examine the top term from each data source.

knitr::kable(rbind(tn_up_top_terms[tn_up_top_terms$source == "GO:BP",][1,],
                   tn_up_top_terms[tn_up_top_terms$source == "REAC",][1,],
                   tn_up_top_terms[tn_up_top_terms$source == "WP",][1,]),
             format = "html")
term_name term_id source
1 external encapsulating structure organization GO:0045229 GO:BP
416 Extracellular matrix organization REAC:R-HSA-1474244 REAC
453 Malignant pleural mesothelioma WP:WP5087 WP

Generate a Manhattan plot to visualize the distribution of the top terms from each data source.

gprofiler2::gostplot(tn_up_top_terms_all) %>% plotly::layout(title = "Manhattan plot for Upregulated genes (Tumor vs. Normal)", font = list(size = 10))

Number of terms:

length(tn_up_top_terms$term_name)
[1] 472

Downregulated Genes

We do the same for the downregualted genes.

tn_down_top_terms_all <- gprofiler2::gost(query = rownames(downregulated_tn), 
                                  organism = "hsapiens", 
                                  exclude_iea = TRUE,
                                  correction_method = "fdr",
                                  sources = c("GO:BP", "REAC", "WP"))

tn_down_top_terms <- data.frame(
  term_name = tn_down_top_terms_all$result$term_name[tn_down_top_terms_all$result$term_size < 500 &
                                                 tn_down_top_terms_all$result$term_size > 1],
  term_id = tn_down_top_terms_all$result$term_id[tn_down_top_terms_all$result$term_size < 500 &
                                             tn_down_top_terms_all$result$term_size > 1],
  source = tn_down_top_terms_all$result$source[tn_down_top_terms_all$result$term_size < 500 &
                                           tn_down_top_terms_all$result$term_size > 1]
)

knitr::kable(head(tn_down_top_terms, 10),format = "html")
term_name term_id source
aerobic respiration GO:0009060 GO:BP
cellular respiration GO:0045333 GO:BP
oxidative phosphorylation GO:0006119 GO:BP
electron transport chain GO:0022900 GO:BP
proton motive force-driven mitochondrial ATP synthesis GO:0042776 GO:BP
generation of precursor metabolites and energy GO:0006091 GO:BP
proton motive force-driven ATP synthesis GO:0015986 GO:BP
energy derivation by oxidation of organic compounds GO:0015980 GO:BP
respiratory electron transport chain GO:0022904 GO:BP
ATP synthesis coupled electron transport GO:0042773 GO:BP


Top terms from the data sources:

knitr::kable(rbind(tn_down_top_terms[tn_down_top_terms$source == "GO:BP",][1,],
                   tn_down_top_terms[tn_down_top_terms$source == "REAC",][1,],
                   tn_down_top_terms[tn_down_top_terms$source == "WP",][1,]),
             format = "html")
term_name term_id source
1 aerobic respiration GO:0009060 GO:BP
97 The citric acid (TCA) cycle and respiratory electron transport REAC:R-HSA-1428517 REAC
116 Electron transport chain: OXPHOS system in mitochondria WP:WP111 WP

Plot the Manhattan plot to visualize distribution of terms from each data source for downregulated genes.

gprofiler2::gostplot(tn_down_top_terms_all) %>% 
  plotly::layout(title = "Manhattan plot for Downregulated genes (Tumor vs. Normal)", font = list(size = 10))

Number of terms

length(tn_down_top_terms$term_name)
[1] 126

All Differentially Expressed Genes

Finally, we analyze for all differentially expressed genes (i.e. both up-regulated and down-regulated genes as a whole).

tn_top_terms_all <- gprofiler2::gost(query = rownames(qlf_tn_hits), 
                                  organism = "hsapiens", 
                                  exclude_iea = TRUE,
                                  correction_method = "fdr",
                                  sources = c("GO:BP", "REAC", "WP"))

tn_top_terms <- data.frame(
  term_name = tn_top_terms_all$result$term_name[tn_top_terms_all$result$term_size < 500 &
                                            tn_top_terms_all$result$term_size > 1],
  term_id = tn_top_terms_all$result$term_id[tn_top_terms_all$result$term_size < 500 &
                                        tn_top_terms_all$result$term_size > 1],
  source = tn_top_terms_all$result$source[tn_top_terms_all$result$term_size < 500 &
                                      tn_top_terms_all$result$term_size > 1]
)

knitr::kable(head(tn_top_terms, 10), format = "html")
term_name term_id source
positive regulation of cell migration GO:0030335 GO:BP
ribonucleoprotein complex biogenesis GO:0022613 GO:BP
autophagy GO:0006914 GO:BP
process utilizing autophagic mechanism GO:0061919 GO:BP
positive regulation of cell motility GO:2000147 GO:BP
positive regulation of locomotion GO:0040017 GO:BP
ribosome biogenesis GO:0042254 GO:BP
vasculature development GO:0001944 GO:BP
regulation of amide metabolic process GO:0034248 GO:BP
regulation of mitotic cell cycle GO:0007346 GO:BP


Top terms from the data sources:

knitr::kable(rbind(tn_top_terms[tn_top_terms$source == "GO:BP",][1,],
                   tn_top_terms[tn_top_terms$source == "REAC",][1,],
                   tn_top_terms[tn_top_terms$source == "WP",][1,]),
             format = "html")
term_name term_id source
1 positive regulation of cell migration GO:0030335 GO:BP
896 RHO GTPase cycle REAC:R-HSA-9012999 REAC
1316 VEGFA-VEGFR2 signaling pathway WP:WP3888 WP
gprofiler2::gostplot(tn_top_terms_all) %>% plotly::layout(title = "Manhattan plot for All DE genes (Tumor vs. Normal)", font = list(size = 10))

There a total of 1447 terms:

length(tn_top_terms$term_name)
[1] 1447

Metastases vs. Normal Tissue

Again, we perform the analysis for Metastases vs. Normal tissue comparison. First, we obtain the up-regulated genes and down-regulated genes separately.

upregulated_mn <- qlf_mn_hits[qlf_mn_hits$table$logFC > 0 & qlf_mn_hits$table$PValue < 0.01, ]
downregulated_mn <- qlf_mn_hits[qlf_mn_hits$table$logFC < 0 & qlf_mn_hits$table$PValue < 0.01, ]

Upregulated Genes

Obtain all terms involved for up-regulated genes using GO:BP, REAC and WP data source.

mn_up_top_terms_all <- gprofiler2::gost(query = rownames(upregulated_mn), 
                                  organism = "hsapiens", 
                                  exclude_iea = TRUE,
                                  correction_method = "fdr",
                                  sources = c("GO:BP", "REAC", "WP"))

mn_up_top_terms <- data.frame(
  term_name = mn_up_top_terms_all$result$term_name[mn_up_top_terms_all$result$term_size < 500 &
                                               mn_up_top_terms_all$result$term_size > 1],
  term_id = mn_up_top_terms_all$result$term_id[mn_up_top_terms_all$result$term_size < 500 &
                                           mn_up_top_terms_all$result$term_size > 1],
  source = mn_up_top_terms_all$result$source[mn_up_top_terms_all$result$term_size < 500 &
                                         mn_up_top_terms_all$result$term_size > 1]
)

knitr::kable(head(mn_up_top_terms, 10), format = "html")
term_name term_id source
T cell activation GO:0042110 GO:BP
leukocyte cell-cell adhesion GO:0007159 GO:BP
regulation of leukocyte cell-cell adhesion GO:1903037 GO:BP
regulation of T cell activation GO:0050863 GO:BP
positive regulation of leukocyte cell-cell adhesion GO:1903039 GO:BP
regulation of lymphocyte activation GO:0051249 GO:BP
regulation of cell-cell adhesion GO:0022407 GO:BP
positive regulation of cell-cell adhesion GO:0022409 GO:BP
positive regulation of T cell activation GO:0050870 GO:BP
lymphocyte proliferation GO:0046651 GO:BP

For context, let’s examine the top term from each data source.

knitr::kable(rbind(mn_up_top_terms[mn_up_top_terms$source == "GO:BP",][1,],
                   mn_up_top_terms[mn_up_top_terms$source == "REAC",][1,],
                   mn_up_top_terms[mn_up_top_terms$source == "WP",][1,]),
             format = "html")
term_name term_id source
1 T cell activation GO:0042110 GO:BP
936 Viral mRNA Translation REAC:R-HSA-192823 REAC
1079 TYROBP causal network in microglia WP:WP3945 WP

We can visualize the distribution of top terms from each data source using an Manhattan plot.

gprofiler2::gostplot(mn_up_top_terms_all) %>% plotly::layout(title = "Manhattan plot for upregulated genes (Metastases vs. Normal)", font = list(size = 10))

Number of terms:

length(mn_up_top_terms$term_name)
[1] 1168

Downregulated Genes

We do the same for the downregualted genes.

mn_down_top_terms_all <- gprofiler2::gost(query = rownames(downregulated_mn), 
                                  organism = "hsapiens", 
                                  exclude_iea = TRUE,
                                  correction_method = "fdr",
                                  sources = c("GO:BP", "REAC", "WP"))

mn_down_top_terms <- data.frame(
  term_name = mn_down_top_terms_all$result$term_name[mn_down_top_terms_all$result$term_size < 500 &
                                                 mn_down_top_terms_all$result$term_size > 1],
  term_id = mn_down_top_terms_all$result$term_id[mn_down_top_terms_all$result$term_size < 500 &
                                             mn_down_top_terms_all$result$term_size > 1],
  source = mn_down_top_terms_all$result$source[mn_down_top_terms_all$result$term_size < 500 &
                                           mn_down_top_terms_all$result$term_size > 1]
)

knitr::kable(head(mn_down_top_terms, 10), format = "html")
term_name term_id source
cilium organization GO:0044782 GO:BP
aerobic respiration GO:0009060 GO:BP
cellular respiration GO:0045333 GO:BP
cilium assembly GO:0060271 GO:BP
generation of precursor metabolites and energy GO:0006091 GO:BP
oxidative phosphorylation GO:0006119 GO:BP
plasma membrane bounded cell projection assembly GO:0120031 GO:BP
cell projection assembly GO:0030031 GO:BP
energy derivation by oxidation of organic compounds GO:0015980 GO:BP
electron transport chain GO:0022900 GO:BP
knitr::kable(rbind(mn_down_top_terms[mn_down_top_terms$source == "GO:BP",][1,],
                   mn_down_top_terms[mn_down_top_terms$source == "REAC",][1,],
                   mn_down_top_terms[mn_down_top_terms$source == "WP",][1,]),
             format = "html")
term_name term_id source
1 cilium organization GO:0044782 GO:BP
116 The citric acid (TCA) cycle and respiratory electron transport REAC:R-HSA-1428517 REAC
132 Electron transport chain: OXPHOS system in mitochondria WP:WP111 WP

Plot the Manhattan plot showing distribution of terms from each data source using list of downregulated genes.

gprofiler2::gostplot(mn_down_top_terms_all) %>% 
  plotly::layout(title = "Manhattan plot for downregulated genes (Metastases vs. Normal)", font = list(size = 10))

Number of terms returned:

length(mn_down_top_terms$term_name)
[1] 149

All Differentially Expressed Genes

Finally, for all differentially expressed genes.

mn_top_terms_all <- gprofiler2::gost(query = rownames(downregulated_mn), 
                                  organism = "hsapiens", 
                                  exclude_iea = TRUE,
                                  correction_method = "fdr",
                                  sources = c("GO:BP", "REAC", "WP"))

mn_top_terms <- data.frame(
  term_name = mn_top_terms_all$result$term_name[mn_top_terms_all$result$term_size < 500 &
                                            mn_top_terms_all$result$term_size > 1],
  term_id = mn_top_terms_all$result$term_id[mn_top_terms_all$result$term_size < 500 &
                                        mn_top_terms_all$result$term_size > 1],
  source = mn_top_terms_all$result$source[mn_top_terms_all$result$term_size < 500 &
                                      mn_top_terms_all$result$term_size > 1]
)

knitr::kable(head(mn_top_terms, 10), format = "html")
term_name term_id source
cilium organization GO:0044782 GO:BP
aerobic respiration GO:0009060 GO:BP
cellular respiration GO:0045333 GO:BP
cilium assembly GO:0060271 GO:BP
generation of precursor metabolites and energy GO:0006091 GO:BP
oxidative phosphorylation GO:0006119 GO:BP
plasma membrane bounded cell projection assembly GO:0120031 GO:BP
cell projection assembly GO:0030031 GO:BP
energy derivation by oxidation of organic compounds GO:0015980 GO:BP
electron transport chain GO:0022900 GO:BP

Top terms from each data source for all differentially expressed genes (Metastases vs. Normal)

knitr::kable(rbind(mn_top_terms[mn_top_terms$source == "GO:BP",][1,],
                   mn_top_terms[mn_top_terms$source == "REAC",][1,],
                   mn_top_terms[mn_top_terms$source == "WP",][1,]),
             format = "html")
term_name term_id source
1 cilium organization GO:0044782 GO:BP
116 The citric acid (TCA) cycle and respiratory electron transport REAC:R-HSA-1428517 REAC
132 Electron transport chain: OXPHOS system in mitochondria WP:WP111 WP

And again, we plot the Manhattan plot to visualize the terms enrichment:

gprofiler2::gostplot(mn_top_terms_all) %>% 
  plotly::layout(title = "Manhattan plot for All DE genes 
                 (Metastases vs. Normal)", font = list(size = 10))

Number of terms:

length(mn_top_terms$term_name)

Thresholded Over-representation analysis Discussion

1. Which method did you choose and why?

I chose g:Profiler because it was discussed in lectures, and previous Journal Entry assignment has introduced the g:Profiler to us with its usage. It provides several analysis methods and visualizations for genomic data, which meets our need. Moreover, I had previous experience using its web-interface, and after learning that it also has R package utility, this is a good chance to try it out.

2. What annotation data did you use and why? What version of the annotation are you using?

I choose GO:BP, Reactome, and WikiPathways for annotation because they were previously mentioned in the Journal Assignment, which were also used on human genes, and these three are very comprehensive datasets for human pathways. The version I am using is as follows: - GO:BP releases/2022-12-04 - REAC releases/2022-12-28 - WP releases/20221210

3. How many genesets were returned with what thresholds?

For all three analysis (using upregulated, downregulated, all differentially expressed) for both tumor vs. normal tissue and metastases vs. normal tissue, we used a threshold of adjusted p value of 0.01, and limit term size between 1 and 500. We set the upper bound to 500 because we do not want to include overly broad and generic terms that will not give us meaningful insights into the roles of the differentially expressed genes. The P value threshold is set to 0.01.

Tumor vs. Normal:
Upregulated genes returned 490 gene sets; Downregulated genes returned 154 genes ets; All differentially expressed genes returned 1151 gene sets.

Metastases vs. Normal:
Upregulated genes returned 1180 gene sets; Downregulated genes returned 162 gene sets; All differentially expressed genes returned 162 gene sets.

4. Run the analysis using the up-regulated set of genes, and the down-regulated set of genes separately. How do these results compare to using the whole list (i.e all differentially expressed genes together vs. the up-regulated and down regulated differentially expressed genes separately)?

Tumor vs. Normal:
Taking all DE genes together returned more gene sets than the results for upregulated and downregulated separately, and the results for upregulated genes are about three times more than the downregulated genes. This suggests that the upregulated genes may be more strongly associated with specific biological processes or pathways than the downregulated genes. Similarly, the fact that the combined set of DE genes returned more gene sets than either the upregulated or downregulated genes alone suggests that there may be some shared biological processes or pathways that are affected by both upregulated and downregulated genes.

Metastases vs. Normal:
Upregulated genes returned around 10 times more terms than the result for all DE genes as a whole. This indicates that the upregulated genes are enriched for certain biological functions or pathways more strongly than the overall set of differentially expressed genes.

Interpretation

1. Do the over-representation results support conclusions or mechanism discussed in the original paper?

Not too much, the over-representation results doesn’t strongly support the conclusions and mechanism discussed in the original paper, probably due to the annotation sources that I choose that yelds different results. However, terms such as regulation of mitotic cell cycle showed up within the analysis result for up-regulated gene sets for tumor tissues and metastases tissues. In the original paper, the authors predicted that the tumors would have TFs that interact with the MAPK pathway and regulate gene expression in a way that is relevant to the development and progression of cancer, and indeed they found that TFs in the MAPK pathway are actively bound significantly more in tumor and metastases than in normal tissue. Transcription factors are widely know to play a role in regulating gene expresison, which would also affect mitotic cell cycle, indicating that our results support the conclusions discussed in the original paper in some way.

2. Can you find evidence, i.e. publications, to support some of the results that you see. How does this evidence support your results.

There are publications describing how transcription factors regulates mitotic cell cycle. In the review paper “Coordinating gene expression during the cell cycle” by Martin.F et. al, they discussed the control mechanisms for mitotic cell cycles in mammals, which include activating genes with peak expression in G1/S by E2F transcription factors (TFs), which is required for DNA synthesis. (Fischer et al. (2022)).

References

Chen, Y., A. T. L. Lun, and G. K. Smyth. 2016. “From Reads to Genes to Pathways: Differential Expression Analysis of RNA-Seq Experiments Using Rsubread and the edgeR Quasi-Likelihood Pipeline.”
Davis, S., and P. Meltzer. 2007. “GEOquery: A Bridge Between the Gene Expression Omnibus (GEO) and BioConductor.” Bioinformatics 14: 1846–47.
Durinck, S., Y. Moreau, A. Kasprzyk, S. Davis, B. Moor, A. Brazma, and W. Huber. 2005. “BioMart and Bioconductor: A Powerful Link Between Biological Databases and Microarray Data Analysis.” Bioinformatics 21: 3439–40.
Durinck, S., P. Spellman, E. Birney, and W. Huber. 2009. “Mapping Identifiers for the Integration of Genomic Datasets with the r/Bioconductor Package biomaRt.” Nature Protocols 4: 1184–91.
Fischer, Martin, Amy E. Schade, Timothy B. Branigan, Gerd A. Müller, and James A. DeCaprio. 2022. “Coordinating Gene Expression During the Cell Cycle.” Trends in Biochemical Sciences 47 (12): 1009–22. https://doi.org/https://doi.org/10.1016/j.tibs.2022.06.007.
Gu, Z., R. Eils, and M. Schlesner. 2016. “Complex Heatmaps Reveal Patterns and Correlations in Multidimensional Genomic Data.” Bioinformatics. https://doi.org/10.1093/bioinformatics/btw313.
Gu, Z., L. Gu, R. Eils, M. Schlesner, and B. Brors. 2014. “Circlize Implements and Enhances Circular Visualization in r.” Bioinformatics 30: 2811–12.
Huber, W., V. J. Carey, R. Gentleman, S. Anders, M. Carlson, B. S. Carvalho, H. C. Bravo, et al. 2015. “Orchestrating High-Throughput Genomic Analysis with Bioconductor.” Nature Methods 12 (2): 115–21.
Kolberg, L., U. Raudvere, I. Kuzmin, J. Vilo, and H. Peterson. 2020. “Gprofiler2– an r Package for Gene List Functional Enrichment Analysis and Namespace Conversion Toolset g:profiler.”
McCarthy, D. J., Chen Y, and G. K. Smyth. 2012. “Differential Expression Analysis of Multifactor RNA-Seq Experiments with Respect to Biological Variation.” Nucleic Acids Research 40: 4288–97.
Morgan, Martin. 2021. “BiocManager: Access the Bioconductor Project Package Repository.”
R Core Team. 2022. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/.
Robinson, M. D., McCarthy DJ, and G. K. Smyth. 2010. “edgeR: A Bioconductor Package for Differential Expression Analysis of Digital Gene Expression Data.” Bioinformatics 26: 139–40.
Sanghi, A., J. J. Gruber, and A. Metwally. 2021. “Chromatin Accessibility Associates with Protein-RNA Correlation in Human Cancer.” Nat Commun 12: 5732. https://doi.org/10.1038/s41467-021-25872-1.
LS0tCnRpdGxlOiAiQXNzaWdubWVudCAyIgphdXRob3I6ICJDaGVuZ1l1ZSBaaGFuZyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnMicKICAgIGRmX3ByaW50OiBwYWdlZAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCiAgcGRmX2RvY3VtZW50OgogICAgZmlnX2NhcHRpb246IHllcwpiaWJsaW9ncmFwaHk6IEEyLmJpYgphbHdheXNfYWxsb3dfaHRtbDogeWVzCi0tLQoKIyBJbnRyb2R1Y3Rpb24KCkluIHRoZSBmaXJzdCBhc3NpZ25tZW50LCB3ZSB1dGlsaXplZCB0aGUgUk5BU2VxIGRhdGEgZnJvbSBTYW5naGkgZXQgYWwuJ3MgcHVibGljYXRpb24gIkNocm9tYXRpbiBBY2Nlc3NpYmlsaXR5IEFzc29jaWF0ZXMgd2l0aCBQcm90ZWluLVJOQSBDb3JyZWxhdGlvbiBpbiBIdW1hbiBDYW5jZXIiKEBzYW5naGkyMDIxYSkgdG8gcGVyZm9ybSBkYXRhIGNsZWFuaW5nLCBub3JtYWxpemF0aW9uLCBnZW5lIG1hcHBpbmcgdG8gSFVHTyBzeW1ib2xzLCBhbmQgcHJlbGltaW5hcnkgYW5hbHlzaXMuIFRoZSBnb2FsIG9mIHRoZSBvcmlnaW5hbCBzdHVkeSB3YXMgdG8gZXhwbG9yZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gY2hyb21hdGluIHN0cnVjdHVyZSBhbHRlcmF0aW9ucyBhbmQgbW9sZWN1bGFyIHBoZW5vdHlwZXMgaW4gY2FuY2VyIGJ5IHV0aWxpemluZyBtdWx0aS1vbWljcyBwcm9maWxpbmcgb2YgaHVtYW4gdHVtb3JzLiBUaGV5IGFwcGxpZWQgdGhpcyBhcHByb2FjaCB0byBhIHRvdGFsIG9mIDM2IGluZGl2aWR1YWxzIHRvIG9idGFpbiB0aHlyb2lkIGNhbmNlciBwcmltYXJ5IHR1bW9ycywgbWV0YXN0YXNlcywgYW5kIHBhdGllbnQtbWF0Y2hlZCBub3JtYWwgdGlzc3VlLCB3aXRoIGEgdG90YWwgb2YgODcgc2FtcGxlcy4gVGhlIHN0dWR5IGlkZW50aWZpZWQgYSBsb2NhbCBjaHJvbWF0aW4gc3RydWN0dXJlIHRoYXQgaXMgaGlnaGx5IGNvcnJlbGF0ZWQgd2l0aCBjb29yZGluYXRlZCBSTkEgYW5kIHByb3RlaW4gZXhwcmVzc2lvbiwgcGFydGljdWxhcmx5IHdpdGhpbiBnZW5lLWJvZHkgZW5oYW5jZXJzLCBhbmQgY2xhaW1lZCB0aGF0IGxvY2FsIGVuaGFuY2VycyBtYXkgYmUgbW9yZSBpbXBvcnRhbnQgZm9yIHJlZ3VsYXRpbmcgY2FuY2VyIGdlbmUgZXhwcmVzc2lvbiB0aGFuIGRpc3RhbCBlbmhhbmNlcnMuIE1vcmVvdmVyLCB0aGUgYXV0aG9ycyBmb3VuZCB0aGF0IFRGcyBpbiB0aGUgTUFQSyBwYXRod2F5IGFyZSBhY3RpdmVseSBib3VuZCBzaWduaWZpY2FudGx5IG1vcmUgaW4gdHVtb3IgYW5kIG1ldGFzdGFzZXMgdGhhbiBpbiBub3JtYWwgdGlzc3VlLgoKV2Ugb2J0YWluZWQgdGhlIGRhdGFzZXQgd2l0aCB0aGUgSUQgW0dTRTE2MjUxNV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9nZW8vcXVlcnkvYWNjLmNnaT9hY2M9R1NFMTYyNTE1KSBmcm9tIEdFTywgd2hpY2ggaXMgbGlua2VkIHRvIHRoZSBzdHVkeSAiQ2hyb21hdGluIEFjY2Vzc2liaWxpdHkgQXNzb2NpYXRlcyB3aXRoIFByb3RlaW4tUk5BIENvcnJlbGF0aW9uIGluIEh1bWFuIENhbmNlciIuIFRoZSBkYXRhc2V0IGNvbnRhaW5zIGEgdG90YWwgb2YgMjgsODgzIGdlbmVzLCBhbmQgdGhlIGV4cGVyaW1lbnQgY29uZGl0aW9ucyBhcmUgY2F0ZWdvcml6ZWQgaW50byAyNyBub3JtYWwgdGlzc3VlIHNhbXBsZXMsIDMwIHR1bW9yIHRpc3N1ZSBzYW1wbGVzLCBhbmQgMzAgbWV0YXN0YXNlcyB0aXNzdWUgc2FtcGxlcy4KClRvIGltcHJvdmUgdGhlIGRhdGEgcXVhbGl0eSwgd2UgcmVtb3ZlZCBnZW5lcyB3aXRoIGxlc3MgdGhhbiAxIGNvdW50IHBlciBtaWxsaW9uIChjcG0pIGluIGxlc3MgdGhhbiB0aHJlZSBzYW1wbGVzLCByZXN1bHRpbmcgaW4gdGhlIHJlbW92YWwgb2YgMTEsNTM4IGdlbmVzLiBXZSB0aGVuIHBlcmZvcm1lZCBub3JtYWxpemF0aW9uIHVzaW5nIFRNTSB3aXRoIHRoZSBlZGdlUiBwYWNrYWdlIHRvIGNvcnJlY3QgdGhlIGxhcmdlIGRldmlhdGlvbiBvZiBtZWFucyBiZXR3ZWVuIHRoZSB0dW1vciwgbWV0YXN0YXNlcyBhbmQgbm9ybWFsIHRpc3N1ZSBncm91cHMgd2hpbGUgc3RpbGwgcHJlc2VydmluZyBzb21lIG9mIHRoZSBvcmlnaW5hbCBzYW1wbGUgZGlzdHJpYnV0aW9uLiBJbnRlcmVzdGluZ2x5LCB0aGUgZGF0YSB3YXMgYWxyZWFkeSB3ZWxsLWFsaWduZWQgYWZ0ZXIgcmVtb3ZpbmcgbG93IGNvdW50cywgc28gdGhlIG5vcm1hbGl6YXRpb24gc3RlcCBiYXJlbHkgaW1wcm92ZWQgdGhlIHF1YWxpdHkgb2YgdGhlIGRhdGFzZXQuIEZpZ3VyZXMgc3VjaCBhcyBNRFMgcGxvdCBhbmQgQkNWIHBsb3QgYXJlIGdlbmVyYXRlZCB0byB2aXN1YWxpemUgdGhlIHF1YWxpdHksIGFzIHNob3duIGJlbG93LgoKRnJvbSB0aGUgcG9zdC1ub3JtYWxpemF0aW9uIE1EUyBwbG90LCB3ZSBvYnNlcnZlZCB0aGF0IHRoZSBvdmVyYWxsIHNlcGFyYXRpb24gYmV0d2VlbiBlYWNoIHRlc3QgY29uZGl0aW9uIGdyb3VwIChUIGFuZCBNKSBhbmQgdGhlIG5vcm1hbCBncm91cCBpcyBjbGVhciwgaW5kaWNhdGluZyBhIGdvb2QgZGF0YXNldCBxdWFsaXR5LiAKYGBge3IgbWRzLCBvdXQud2lkdGggPSAiOTAlIiwgZWNobyA9IEZBTFNFLCBmaWcuY2FwPSJGaWd1cmUgMS4gTURTIHBsb3QgdG8gaW5zcGVjdCB0aGUgc2FtcGxlIHNlcGFyYXRpb24uIEdyZWVuOiBtZXRhc3Rhc2VzOyBCbGFjazogVHVtb3I7IEJsdWU6IE5vcm1hbC4gVGhlIG92ZXJhbGwgc2VwYXJhdGlvbiBiZXR3ZWVuIGVhY2ggdGVzdCBjb25kaXRpb24gZ3JvdXAgKFQgYW5kIE0pIHRvIG5vcm1hbCBncm91cCBpcyBjbGVhciwgaW5kaWNhdGluZyBhIGdvb2QgZGF0YXNldCBxdWFsaXR5LiJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWd1cmVzL01EUy5qcGVnIikKYGBgCgpBZGRpdGlvbmFsbHksIHRoZSB2YXJpYW5jZSBvZiB0aGUgZGF0YSB3YXMgcmVsYXRpdmVseSBjb25zaXN0ZW50IHdpdGggdGhlIGV4cGVjdGVkIHRyZW5kLCBhcyBpbmRpY2F0ZWQgYnkgdGhlIGRpc3BlcnNpb24tc3F1YXJlZCBCQ1YgcGxvdC4KCmBgYHtyIGJjdiwgb3V0LndpZHRoID0gIjkwJSIsIGVjaG8gPSBGQUxTRSwgZmlnLmNhcD0iRmlndXJlIDIuIERpc3BlcnNpb24tc3F1YXJlZCBCQ1YgcGxvdC4gR2VuZXMgd2l0aCBsb3cgY291bnRzIGhhdmUgYSBoaWdoZXIgdmFyaWF0aW9uLCB3aGVyZWFzIGdlbmVzIHdpdGggaGlnaGVyIGNvdW50cyBoYXZlIGEgbG93ZXIgdmFyaWF0aW9uIHRvd2FyZHMgdGhlIGV4cGVjdGVkIHRyZW5kLiBUaGUgdHJlbmQgb2YgdGhlIGNvdW50IGRhdGEgZmFsbHMgYXJvdW5kIHRoZSBjb21tb24gZGlzcGVyc2lvbiBsaW5lIGluIGEgQkNWIHBsb3QsIGluZGljYXRpbmcgdGhhdCB0aGUgdmFyaWFuY2Ugb2YgdGhlIGRhdGEgaXMgcmVsYXRpdmVseSBjb25zaXN0ZW50IHdpdGggdGhlIGV4cGVjdGVkIHRyZW5kLiJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWd1cmVzL0JDVi5qcGVnIikKYGBgCgpUbyBtYXAgaWRlbnRpZmllcnMsIHdlIHV0aWxpemVkIHRoZSBwYWNrYWdlIGJpb21hUnQuIEZvcnR1bmF0ZWx5LCBnZW5lIElEcyBpbiB0aGUgb3JpZ2luYWwgZGF0YXNldCB3ZXJlIG1vc3RseSBhbHJlYWR5IG1hcHBlZCB0byB0aGUgY29ycmVzcG9uZGluZyBIVUdPIGdlbmUgc3ltYm9scy4gQWZ0ZXIgcmVtb3ZpbmcgbG93IGNvdW50cywgZ2VuZXMgd2l0aCBkdXBsaWNhdGUgaWRlbnRpZmllcnMsIGFuZCBnZW5lcyB0aGF0IGNhbm5vdCBiZSBtYXBwZWQgdG8gSFVHTyBzeW1ib2xzLCB0aGUgZmluYWwgZGF0YXNldCBjb250YWluZWQgMTcsMzY4IHVuaXF1ZSBnZW5lcy4KCgojIERvd25sb2FkIFBhY2thZ2VzCkluIHRoaXMgc2VjdGlvbiwgd2UgaW1wb3J0IGFuZCBpbnN0YWxsIHRoZSBuZWNlc3NhcnkgcGFja2FnZXMgZm9yIHRoaXMgYXNzaWdubWVudCwgaW4gd2hpY2ggd2Ugd2lsbCBjb25kdWN0IGEgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMgdXNpbmcgdGhlIG5vcm1hbGl6ZWQgZGF0YXNldCBhbmQgYSB0aHJlc2hvbGRlZCBvdmVyLXJlcHJlc2VudGF0aW9uIGFuYWx5c2lzLgoKKiBSIChAcikKKiBbQmlvY01hbmFnZXJdKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9QmlvY01hbmFnZXIpIChAbW9yZ2FuMjAyMWEpCiogW0dFT21ldGFkYl0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy9odG1sL0dFT21ldGFkYi5odG1sKSAoQG1jY2FydGh5MjAxMmEpCiogW2VkZ2VSXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL2h0bWwvZWRnZVIuaHRtbCkgKEByb2JpbnNvbjIwMTBhLCBAbWNjYXJ0aHkyMDEyYSwgQGNoZW4yMDE2YSkKKiBbYmlvbWFSdF0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy9odG1sL2Jpb21hUnQuaHRtbCkgKEBkdXJpbmNrMjAwOWEsIEBkdXJpbmNrMjAwNWEpCiogW0dFT3F1ZXJ5XShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL2h0bWwvR0VPcXVlcnkuaHRtbCkgKEBkYXZpczIwMDdhKQoqIFtCaW9iYXNlICYgQmlvR2VuZXJpY3NdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvaHRtbC9CaW9iYXNlLmh0bWwpIChAaHViZXIyMDE1YSkKKiBbY2lyY2xpemVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9jaXJjbGl6ZS9pbmRleC5odG1sKSAoQGd1MjAxNGEpCiogW0NvbXBsZXhIZWF0bWFwXShodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL2h0bWwvQ29tcGxleEhlYXRtYXAuaHRtbCkgKEBndTIwMTZhKQoqIFtncHJvZmlsZXIyXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ3Byb2ZpbGVyMi9pbmRleC5odG1sKSAoQGtvbGJlcmcyMDIwYSkKCmBgYHtyIEluc3RhbGwgcGFja2FnZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmlmICghcmVxdWlyZU5hbWVzcGFjZSgiQmlvY01hbmFnZXIiLCBxdWlldGx5ID0gVFJVRSkpewogIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIil9CgppZiAoIXJlcXVpcmVOYW1lc3BhY2UoIkdFT21ldGFkYiIsIHF1aWV0bHkgPSBUUlVFKSl7CiAgQmlvY01hbmFnZXI6Omluc3RhbGwoIkdFT21ldGFkYiIpfQoKaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJjaXJjbGl6ZSIsIHF1aWV0bHkgPSBUUlVFKSkKICAgIGluc3RhbGwucGFja2FnZXMoImNpcmNsaXplIikKCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiQ29tcGxleEhlYXRtYXAiLCBxdWlldGx5ID0gVFJVRSkpCiAgICBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiQ29tcGxleEhlYXRtYXAiKQoKaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJncHJvZmlsZXIyIiwgcXVpZXRseSA9IFRSVUUpKQogICAgQmlvY01hbmFnZXI6Omluc3RhbGwoImdwcm9maWxlcjIiKQoKaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJnZ3Bsb3QyIiwgcXVpZXRseSA9IFRSVUUpKXsKICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIil9CgppZiAoIXJlcXVpcmVOYW1lc3BhY2UoImVkZ2VSIiwgcXVpZXRseSA9IFRSVUUpKXsKICBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiZWRnZVIiKX0KCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiYmlvbWFSdCIsIHF1aWV0bHkgPSBUUlVFKSl7CiAgQmlvY01hbmFnZXI6Omluc3RhbGwoImJpb21hUnQiKX0KCmlmICghcmVxdWlyZU5hbWVzcGFjZSgia25pdHIiLCBxdWlldGx5ID0gVFJVRSkpewogIGluc3RhbGwucGFja2FnZXMoImtuaXRyIil9CgppZiAoIXJlcXVpcmVOYW1lc3BhY2UoIkdFT3F1ZXJ5IiwgcXVpZXRseSA9IFRSVUUpKXsKICBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiR0VPcXVlcnkiKX0KCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiQmlvYmFzZSIsIHF1aWV0bHkgPSBUUlVFKSl7CiAgQmlvY01hbmFnZXI6Omluc3RhbGwoIkJpb2Jhc2UiKX0KCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiZHBseXIiLCBxdWlldGx5ID0gVFJVRSkpewogIGluc3RhbGwucGFja2FnZXMoImRwbHlyIil9CgppZiAoIXJlcXVpcmVOYW1lc3BhY2UoImthYmxlRXh0cmEiLCBxdWlldGx5ID0gVFJVRSkpewogIGluc3RhbGwucGFja2FnZXMoImthYmxlRXh0cmEiKX0KCmBgYAoKTG9hZCBwYWNrYWdlcwpgYGB7ciBMb2FkIGxpYnJhcnksIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkoIkdFT21ldGFkYiIpCmxpYnJhcnkoImdncGxvdDIiKQpsaWJyYXJ5KCJlZGdlUiIpCmxpYnJhcnkoImJpb21hUnQiKQpsaWJyYXJ5KCJDb21wbGV4SGVhdG1hcCIpCmxpYnJhcnkoImNpcmNsaXplIikKbGlicmFyeSgiZHBseXIiKQpsaWJyYXJ5KCJHRU9xdWVyeSIpCmxpYnJhcnkoIkJpb2Jhc2UiKQpsaWJyYXJ5KCJrbml0ciIpCmxpYnJhcnkoImthYmxlRXh0cmEiKQpgYGAKCiMgRGlmZmVyZW50aWFsIEV4cHJlc3Npb24gQW5hbHlzaXMKCkluIHRoaXMgc2VjdGlvbiwgd2Ugd2lsbCB1c2UgZWRnZVIgcGFja2FnZSB0byBwZXJmb3JtIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzLgoKIyMgUmV0cmlldmUgaW5mb3JtYXRpb24gZnJvbSBBc3NpZ25tZW50IDEKVGhlIG5vcm1hbGl6ZWQgZGF0YSBwcm9jZXNzZWQgZnJvbSBBc3NpZ25tZW50IDEgaGFzIGJlZW4gc3RvcmVkIGluIHRoZSBmaWxlIG5hbWVkIGFzICJub3JtYWxpemVkX2NvdW50c19maW5hbC50eHQiLiBXZSBub3cgbG9hZCB0aGlzIGRhdGEgaW50byBSLgpUaGUgY2F0ZWdvcmllcyBmb3IgdGhlIHNhbXBsZXMgd2VyZSBzYXZlZCBpbiAic2FtcGxlcy50eHQiIGZpbGUuIFdlIGNhbiBhbHNvIGxvYWQgaXQgaW50byBSLgpgYGB7ciByZXRyaWV2ZV9kYXRhLCBtZXNzYWdlPUZBTFNFfQpub3JtYWxpemVkX2NvdW50cyA8LSByZWFkLnRhYmxlKCJub3JtYWxpemVkX2NvdW50c19maW5hbC50eHQiKQpzYW1wbGVzIDwtIHJlYWQudGFibGUoInNhbXBsZXMudHh0IikKYGBgCgojIyBFeGFtaW5lIHRoZSBub3JtYWxpemVkIGRhdGFzZXQKVGhlIGZvcm1hdCBvZiB0aGUgbm9ybWFsaXplZCBjb3VudCBkYXRhc2V0IGhhcyBhbHJlYWR5IGJlZW4gcHJvY2Vzc2VkIGluIGEgd2F5IHRoYXQgY2FuIGJlIGRpcmVjdGx5IHVzZWQgdG8gcGxvdCB0aGUgaGVhdG1hcCwgd2hpY2ggd291bGQgYmUgb3VyIG5leHQgc3RlcC4KYGBge3IgY2hlY2tfZGF0YSwgbWVzc2FnZT1GQUxTRX0Ka2FibGUobm9ybWFsaXplZF9jb3VudHNbMTo1LDE6NV0sIGZvcm1hdCA9ICJodG1sIikKYGBgCgojIyBFeGFtaW5lIHRoZSBzYW1wbGVzIGluZm9ybWF0aW9uCgpUaGVyZSBhcmUgdHdvIGNvbHVtbnMsICJpbmRpdmlkdWFscyIgYW5kICJ0aXNzdWUgdHlwZSIuIFRoZSAiaW5kaXZpZHVhbCIgY29sdW1uIHN0b3JlcyBkYXRhIG9mIHRoZSBwYXRpZW50cyB3aG8gdGhlIGF1dGhvcnMgdG9vayB0aGUgc2FtcGxlcyBmcm9tLCBhbmQgdGhlICJ0aXNzdWUgdHlwZSIgaW5kaWNhdGVzIHRoZSB0eXBlIG9mIHRoZSB0aXNzdWUsIGluY2x1ZGluZyB0dW1vcnMsIG1ldGFzdGFzZXMsIGFuZCBub3JtYWwgdGlzc3VlLgpgYGB7ciBzYW1wbGVzfQprbml0cjo6a2FibGUoaGVhZChzYW1wbGVzLCAxMCksICBmb3JtYXQgPSAiaHRtbCIpCmBgYAoKIyMgRGVzaWduIE1vZGVsCkluIHRoaXMgc2VjdGlvbiwgd2Ugd2lsbCBjcmVhdGUgYSBkYXRhIG1hdHJpeCBmcm9tIG91ciBkYXRhc2V0LgoKCkluIG9yZGVyIHRvIHBlcmZvcm0gc3RhdGlzdGljYWwgdGVzdGluZywgd2UgbmVlZCBhIGRlc2lnbiBtYXRyaXggdGhhdCBkZWZpbmVzIG91ciBtb2RlbC4gTm90aWNlIHRoYXQgaW4gb3VyIGRhdGFzZXQsIHRoZXJlIGFyZSB0d28gZmFjdG9yczogCgoxLiBUaXNzdWUgdHlwZXMgKE5vcm1hbCwgdHVtb3IsIG1ldGFzdGFzZXMpCjIuIFBhdGllbnQgKGluZGl2aWR1YWwpCgpIZW5jZSwgaWRlYWxseSwgd2Ugd291bGQgbGlrZSB0byBhY2NvdW50IGZvciBib3RoIGZhY3RvcnMgaW4gb3VyIGRlc2lnbiBtYXRyaXguCgpSZWNhbGwgdGhhdCB3ZSB3YW50IHRvIGZpbmQgdGhlIGdlbmVzIHRoYXQgYXJlIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBpbiB0aGUgdHVtb3IgYW5kIG1ldGFzdGFzZXMgc2FtcGxlcyBpbiBjb250cmFzdCB0byBub3JtYWwgdGlzc3Vlcywgc28gd2UgZmlyc3QgZmFjdG9yIHRoZSB0aXNzdWUgdHlwZXMgc3VjaCB0aGF0ICJOIiB0eXBlIGJlY29tZXMgdGhlIGJhc2VsaW5lL3JlZmVyZW5jZSBsZXZlbC4gVGhpcyB3b3VsZCBhZmZlY3Qgb24gd2hpY2ggdGlzc3VlIHR5cGUgd291bGQgYmUgY2hvc2VuIGFzIHRoZSBjb250cm9sIHZhbHVlIChpLmUuIGludGVyY2VwdCkgd2hlbiBwZXJmb3JtaW5nIF9fKiptb2RlbC5tYXRyaXgqKl9fIGZ1bmN0aW9uIHRvIGdlbmVyYXRlIHRoZSBkZXNpZ24gbWF0cml4LgpgYGB7ciBkZXNpZ25fbWF0cml4LCBtZXNzYWdlPUZBTFNFfQojIFNldCBub3JtYWwgdGlzc3VlIHR5cGUgYXMgdGhlIGludGVyY2VwdApzYW1wbGVzJHRpc3N1ZV90eXBlIDwtIGZhY3RvcihzYW1wbGVzJHRpc3N1ZV90eXBlKQpzYW1wbGVzJHRpc3N1ZV90eXBlIDwtIHJlbGV2ZWwoc2FtcGxlcyR0aXNzdWVfdHlwZSwgcmVmPSJOIikKCiMgRG9lc24ndCByZWFsbHkgbWF0dGVyIGZvciBpbmRpdmlkdWFsIHBlb3BsZSwgYnV0IHdlIGNhbiBzZXQgQzEgYXMgdGhlIGludGVyY2VwdCBmb3IgdGhlIHNha2Ugb2YgaGFiaXQuCnNhbXBsZXMkaW5kaXZpZHVhbCA8LSBmYWN0b3Ioc2FtcGxlcyRpbmRpdmlkdWFsKQpzYW1wbGVzJGluZGl2aWR1YWwgPC0gcmVsZXZlbChzYW1wbGVzJGluZGl2aWR1YWwsIHJlZj0iQzEiKQoKIyBHZW5lcmF0ZSBkZXNpZ24gbWF0cml4IHdpdGggYm90aCBmYWN0b3JzOiBpbmRpdmlkdWFsIGFuZCB0aXNzdWUgdHlwZQptb2RlbF9kZXNpZ24gPC0gbW9kZWwubWF0cml4KH4gc2FtcGxlcyRpbmRpdmlkdWFsICsgc2FtcGxlcyR0aXNzdWVfdHlwZSkKCiMgQ2hlY2sgdGhlIG1hdHJpeAptb2RlbF9kZXNpZ25bMTo1LDE6NV0KYGBgCgoKIyMgQW5hbHlzaXMgVXNpbmcgZWRnZVIKCkZvciBvdXIgZG93bnN0cmVhbSBhbmFseXNpcywgd2UgYXJlIGdvaW5nIHRvIHVzZSBlZGdlUiwgd2hpY2ggaXMgc3BlY2lmaWNhbGx5IGRlc2lnbmVkIGZvciBSTkFTZXEgZGF0YS4gRmlyc3QsIHdlIGNyZWF0ZSB0aGUgYmFzZSBlZGdlUiBvYmplY3QgY2FsbGVkIERHRUxpc3QuIFRoZSBncm91cCB3ZSB3YW50IHRvIGRlZmluZSBpcyB0aGUgdGlzc3VlIHR5cGUuIApgYGB7ciBkaXNwZXJzaW9uX2NhbGMsIG1lc3NhZ2U9RkFMU0V9CmQgPC0gZWRnZVI6OkRHRUxpc3QoY291bnRzID0gbm9ybWFsaXplZF9jb3VudHMsIGdyb3VwID0gc2FtcGxlcyR0aXNzdWVfdHlwZSkKYGBgCkZvciBmdXJ0aGVyIHByb2Nlc3NpbmcsIHdlIGNob29zZSB0byB1c2UgdGhlIHF1YXNpLWxpa2VsaWhvb2QgbW9kZWxzIHNpbmNlIG91ciBkYXRhc2V0IGlzIGZyb20gYW4gUk5BU2VxIGV4cGVyaW1lbnQgYW5kIHF1YXNpLWxpa2VsaWhvb2QgbW9kZWxzIGFyZSBiZXN0IHN1aXRlZCB0byBoYW5kbGUgUk5BU2VxIGRhdGEuCgojIyMgQ2hlY2sgRWxpZ2liaWxpdHkKCk9uZSBpbXBvcnRhbnQgdW5kZXJseWluZyBhc3N1bXB0aW9uIGZvciB1c2luZyB0aGUgUXVhc2ktbGlrZWxpaG9vZCBtb2RlbCBpcyB0aGF0IHRoZSBkYXRhIGZvbGxvd3MgYSBuZWdhdGl2ZSBiaW5vbWlhbCBkaXN0cmlidXRpb24uIFdlIG5lZWQgdG8gdmVyaWZ5IHRoYXQgb3VyIGRhdGFzZXQgaW5kZWVkIG1lZXRzIHRoYXQgYXNzdW1wdGlvbi4KClRvIGRvIHRoaXMsIHdlIGNhbGN1bGF0ZSB0aGUgZGlzcGVyc2lvbiBhbmQgZ2VuZXJhdGUgdGhlIHBsb3QgdG8gdmlzdWFsaXplIHRoZSBtZWFuLXZhcmlhbmNlIHJlbGF0aW9uc2hpcC4gCgpgYGB7ciBlc3RpbWF0ZV9kaXNwLCBtZXNzYWdlID0gRkFMU0V9CiMgQ2FsY3VsYXRlIGRpc3BlcnNpb24KZCA8LSBlZGdlUjo6ZXN0aW1hdGVEaXNwKGQsIG1vZGVsX2Rlc2lnbikKYGBgCgpgYGB7ciBtZWFuX3Zhcl9wbG90LCBldmFsID0gRkFMU0V9CiMgR2VuZXJhdGUgTVYgcGxvdAplZGdlUjo6cGxvdE1lYW5WYXIoZCwKICAgICAgICAgICAgICAgICAgIHNob3cucmF3LnZhcnMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgc2hvdy50YWd3aXNlLnZhcnMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgTkJsaW5lID0gVFJVRSwKICAgICAgICAgICAgICAgICAgIHNob3cuYXZlLnJhdy52YXJzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgIHNob3cuYmlubmVkLmNvbW1vbi5kaXNwLnZhcnMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgbWFpbiA9ICJNZWFuLVZhcmlhbmNlIFBsb3QgZm9yIE5vcm1hbGl6ZWQgRGF0YSIpCiMgRGlzcGxheSBsZWdlbmQKbGVnZW5kKCJ0b3BsZWZ0IiwgCiAgICAgICBsZWdlbmQ9YygiUmF3IERhdGEiLCAiVGFnd2lzZSBEaXNwZXJzaW9uIiwgIkF2ZXJhZ2UgUmF3IFZhcmlhbmNlcyIsIAogICAgICAgICAgICAgICAgIkJpbm5lZCBDb21tb24gRGlzcGVyc2lvbiIsICJOZWdhdGl2ZSBCaW5vbWlhbCBMaW5lIiksIAogICAgICAgY29sID0gYygiZ3JleSIsICJsaWdodGJsdWUiLCAibWFyb29uIiwgInJlZCIsICJkb2RnZXJibHVlMiIpLCBwY2g9YygxLDEsNCw0LE5BKSwgbHR5PWMoMCwwLDAsMCwxKSwgbHdkPWMoMSwxLDEsMSwyKSwgY2V4PTAuNikKYGBgCgpGcm9tIHRoZSBNViBwbG90LCB3ZSBjYW4gc2VlIHRoYXQgb3VyIG5vcm1hbGl6ZWQgY291bnQgZGF0YSBmb2xsb3dzIHRoZSBuZWdhdGl2ZSBiaW5vbWlhbCBkaXN0cmlidXRpb24sIHdoZXJlIGl0IGNsZWFybHkgYWxpZ25zIHdpdGggdGhlIGJsdWUgbGluZSBpbmRpY2F0aW5nIHRoZSBuZWdhdGl2ZSBiaW5vbWlhbCB0cmVuZC4KCmBgYHtyIG1lYW5fdmFyX2Rpc3BsYXksIG91dC53aWR0aCA9ICI5MCUiLCBlY2hvID0gRkFMU0UsIGZpZy5jYXA9IkZpZ3VyZSAzLiBNZWFuLXZhcmlhbmNlIHBsb3Qgc2hvd2luZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGRhdGEuIFRoZSBkaXNwZXJzaW9uIGFuZCB2YXJpYW5jZSBvZiB0aGUgZGF0YSBwZXJmZWN0bHkgZm9sbG93cyB0aGUgbmVnYXRpdmUgYmlub21pYWwgZGlzdHJpYnV0aW9uLCBpbiB3aGljaCB0aGUgcmF3IGRhdGEgYW5kIHRoZSBibHVlIG5lZ2F0aXZlIGJpbm9taWFsIGxpbmUgYWxsaWducy4ifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiZmlndXJlcy9tZWFuX3Zhci5qcGciKQpgYGAKCgo8YnI+CgpOb3csIHdlIGhhdmUgY3JlYXRlZCB0aGUgZGVzaWduIG1hdHJpeCBhbmQgdmVyaWZpZWQgdGhlIGFzc3VtcHRpb24gZm9yIHRoZSBkYXRhIHRvIGJlIG5lZ2F0aXZlLWJpbm9taWFsbHkgZGlzdHJpYnV0ZWQsIHdlIGNhbiBwcm9jZWVkIHRvIHRoZSBuZXh0IHN0YWdlIG9mIG91ciBhbmFseXNpcy4gV2UgZml0IHRoZSBtb2RlbCB1c2luZyBvdXIgZGVzaWduIG1hdHJpeDogCgpgYGB7ciBmaXRfcWwsIG1lc3NhZ2U9RkFMU0V9CmZpdCA8LSBlZGdlUjo6Z2xtUUxGaXQoZCwgbW9kZWxfZGVzaWduKQpgYGAKPGJyPgoKT25jZSB3ZSBoYXZlIGZpdCB0aGUgbW9kZWwsIHdlIGNhbiBwcm9jZWVkIHRvIGNhbGN1bGF0ZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbi4gV2Ugd2lsbCBwZXJmb3JtIHRoZSBjYWxjdWxhdGlvbiBzZXBhcmF0ZWx5IGZvciBfXyoqVHVtb3IgdnMuIE5vcm1hbCoqX18sIGFuZCBfXyoqTWV0YXN0YXNlcyB2cy4gTm9ybWFsKipfXy4gVG8gZW5zdXJlIHRoYXQgdGhlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIGFyZSBub3Qgb2J0YWluZWQgYnkgcmFuZG9tLCB3ZSB3aWxsIHBlcmZvcm0gIGNvcnJlY3Rpb24gZm9yIG11bHRpcGxlIGh5cG90aGVzaXMgdGVzdGluZyB1c2luZyBCZW5qYW1pbmktSG9jaGJlcmcgYXBwcm9hY2guCgojIyBUdW1vciB2cy4gTm9ybWFsCgpJbiB0aGlzIHNlY3Rpb24sIHdlIHdhbnQgdG8gdGVzdCBmb3IgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYmV0d2VlbiB0aGUgdHVtb3Igc2FtcGxlcyBhbmQgbm9ybWFsIHNhbXBsZXMuCmBgYHtyIHRlc3RfdG4sIG1lc3NhZ2U9RkFMU0V9CiMgQ29uZHVjdCBnZW5ld2lzZSBzdGF0aXN0aWNhbCB0ZXN0cyBmb3IgdHVtb3IgdGlzc3VlIGFzIGNvZWZmaWNpZW50CnFsZl90biA8LSBlZGdlUjo6Z2xtUUxGVGVzdChmaXQsIGNvZWY9J3NhbXBsZXMkdGlzc3VlX3R5cGVUJykKCiMgRXh0cmFjdCB0aGUgdG9wIERFIGhpdHMgcmFua2VkIGJ5IFBWYWx1ZQpxbGZfdG5faGl0cyA8LSBlZGdlUjo6dG9wVGFncyhxbGZfdG4sc29ydC5ieSA9ICJQVmFsdWUiLCBhZGp1c3QubWV0aG9kID0gIkJIIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbiA9IG5yb3cobm9ybWFsaXplZF9jb3VudHMpKQoKIyBEaXNwbGF5IHRhYmxlIG9mIHRvcCBoaXRzCmtuaXRyOjprYWJsZShoZWFkKHFsZl90bl9oaXRzJHRhYmxlKSwgZm9ybWF0ID0gImh0bWwiKQpgYGAKPGJyPgoKV2UgY2FuIGV4YW1pbmUgdGhlIG51bWJlciBvZiBnZW5lcyBwYXNzIHRoZSB0aHJlc2hvbGQgYW5kIGNvcnJlY3Rpb24uIFdlIGFyZSB1c2luZyAwLjA1IGFzIHRoZSB0aHJlc2hvbGQgZm9yIHAtdmFsdWUgYXMgaXQgaXMgY29tbW9ubHkgdXNlZCBpbiBwcmFjdGljZS4KPGJyPgoKTnVtYmVyIG9mIGdlbmVzIHRoYXQgcGFzc2VkIHRoZSB0aHJlc2hvbGQ6CmBgYHtyIHB2YWxfdGhyZXNoLCBtZXNzYWdlPUZBTFNFfQpsZW5ndGgod2hpY2gocWxmX3RuX2hpdHMkdGFibGUkUFZhbHVlIDwgMC4wNSkpCmBgYAo8YnI+Ck51bWJlciBvZiBnZW5lcyB0aGF0IHBhc3NlZCBjb3JyZWN0aW9uOgpgYGB7ciBmZHJfdGhyZXNoLCBtZXNzYWdlPUZBTFNFfQpsZW5ndGgod2hpY2gocWxmX3RuX2hpdHMkdGFibGUkRkRSIDwgMC4wNSkpCmBgYAo8YnI+CgpUaGUgdGhyZXNob2xkIG9mIDAuMDUgZ2l2ZXMgdXMgcXVpdGUgYSBsb3Qgb2YgZ2VuZXMuIEhvd2V2ZXIsIHNpbmNlIHdlIGFyZSBkZWFsaW5nIHdpdGggaHVtYW4gZGlzZWFzZSwgd2hpY2ggc2hvdWxkIGJlIG1vcmUgc3RyaWN0IHRvIG9idGFpbiBtb3JlIG1lYW5pbmdmdWwgaGl0cyBmb3IgZnVydGhlciBhbmFseXNpcywgd2UgY2hvb3NlIHRvIHVzZSBhIG1vcmUgc3RyaW5nZW50IHRocmVzaG9sZCBvZiAwLjAxLgo8YnI+CgpOdW1iZXIgb2YgZ2VuZXMgdGhhdCBwYXNzZWQgdGhlIDAuMDEgcCB2YWx1ZSB0aHJlc2hvbGQ6CmBgYHtyIHRuX3B2YWxfc3RyaW5nZW50LCBtZXNzYWdlPUZBTFNFfQpsZW5ndGgod2hpY2gocWxmX3RuX2hpdHMkdGFibGUkUFZhbHVlIDwgMC4wMSkpCmBgYAo8YnI+Ck51bWJlciBvZiBnZW5lcyB0aGF0IHBhc3NlZCBjb3JyZWN0aW9uIG9mIDAuMDEgdGhyZXNob2xkOgpgYGB7ciB0bl9mZHJfc3RyaW5nZW50LCBtZXNzYWdlPUZBTFNFfQpsZW5ndGgod2hpY2gocWxmX3RuX2hpdHMkdGFibGUkRkRSIDwgMC4wMSkpCmBgYAo8YnI+ClRoZXJlIGFyZSBzdGlsbCBhIGxvdCBvZiBnZW5lcyBsZWZ0IGZvciBmdXJ0aGVyIGFuYWx5c2lzLiBJbiBsYXRlciBzZWN0aW9ucywgZ2VuZXMgdGhhdCBoYXZlIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBmb3IgbGVzcyB0aGFuIDIgbG9nIGZvbGQgY2hhbmdlIChMRkMpIHdvdWxkIGFsc28gYmUgZmlsdGVyZWQgb3V0IHRvIG9idGFpbiBhIHNldCBvZiBtb3JlIG1lYW5pbmdmdWwgZGF0YS4KCgojIyBNZXRhc3Rhc2VzIHZzLiBOb3JtYWwKCkluIHRoaXMgc2VjdGlvbiwgd2UgdGVzdCBmb3IgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYmV0d2VlbiB0aGUgbWV0YXN0YXNpcyB0aXNzdWVzIGFuZCB0aGUgbm9ybWFsIHRpc3N1ZXMuCmBgYHtyIHRlc3RfbW4sIG1lc3NhZ2U9RkFMU0V9CiMgQ29uZHVjdCBnZW5ld2lzZSBzdGF0aXN0aWNhbCB0ZXN0cyBmb3IgbWV0YXN0YXNlcyB0aXNzdWUgYXMgY29lZmZpY2llbnQKcWxmX21uIDwtIGVkZ2VSOjpnbG1RTEZUZXN0KGZpdCwgY29lZj0nc2FtcGxlcyR0aXNzdWVfdHlwZU0nKQoKIyBFeHRyYWN0IHRoZSB0b3AgREUgaGl0cyByYW5rZWQgYnkgUFZhbHVlCnFsZl9tbl9oaXRzIDwtIGVkZ2VSOjp0b3BUYWdzKHFsZl9tbixzb3J0LmJ5ID0gIlBWYWx1ZSIsIGFkanVzdC5tZXRob2QgPSAiQkgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBuID0gbnJvdyhub3JtYWxpemVkX2NvdW50cykpCgojIERpc3BsYXkgdGFibGUgb2YgdG9wIGhpdHMKa25pdHI6OmthYmxlKGhlYWQocWxmX21uX2hpdHMkdGFibGUpLCBmb3JtYXQgPSAiaHRtbCIpCgpgYGAKCjxicj4KV2UgYXBwbHkgdGhlIDAuMDEgdGhyZXNob2xkIGZvciB0aGUgc2FtZSByZWFzb24gYXMgaW5kaWNhdGVkIHByZXZpb3VzbHkuCgpOdW1iZXIgb2YgZ2VuZXMgdGhhdCBwYXNzZWQgdGhlIDAuMDEgcCB2YWx1ZSB0aHJlc2hvbGQ6CmBgYHtyIG1uX3B2YWxfc3RyaW5nZW50LCBtZXNzYWdlPUZBTFNFfQpsZW5ndGgod2hpY2gocWxmX21uX2hpdHMkdGFibGUkUFZhbHVlIDwgMC4wMSkpCmBgYAo8YnI+CgpOdW1iZXIgb2YgZ2VuZXMgdGhhdCBwYXNzZWQgY29ycmVjdGlvbiB3aXRoIDAuMDEgdGhyZXNob2xkOgpgYGB7ciBtbl9mZHJfc3RyaW5nZW50LCBtZXNzYWdlPUZBTFNFfQpsZW5ndGgod2hpY2gocWxmX21uX2hpdHMkdGFibGUkRkRSIDwgMC4wMSkpCmBgYAo8YnI+CgpBZ2Fpbiwgd2Ugd291bGQgYWxzbyBmaWx0ZXIgb3V0IHRoZSBnZW5lcyB0aGF0IGhhdmUgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGxlc3MgdGhhbiAyIExGQyBpbiBsYXRlciBzZWN0aW9ucy4KCiMjIyBWb2xjYW5vIFBsb3QgKFR1bW9yIHZzLiBOb3JtYWwpCldlIHBsb3QgdGhlIHZvbGNhbm8gcGxvdCB0byB2aXN1YWxpemUgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gb2YgZ2VuZXMgZm9yIHR1bW9yIHZzLiBub3JtYWwgdGlzc3VlIHNhbXBsZXMuIEVhY2ggZ2VuZSBpcyByZXByZXNlbnRlZCBieSBhIHBvaW50IGluIHRoZSBwbG90LiBUaGUgaG9yaXpvbnRhbCBheGlzIG9mIHRoZSBwbG90IGlzIHRoZSBsb2cyIGZvbGQgY2hhbmdlIGFuZCB0aGUgdmVydGljYWwgYXhpcyBpcyB0aGUgLWxvZzEwcCB3aGljaCBpbmRpY2F0ZXMgaG93IGxpa2VseSB0aGUgZGlmZmVyZW50aWFsIG9mIGEgZ2VuZSBpcyBkdWUgdG8gYWN0dWFsIGJpb2xvZ2ljYWwgdmFyaWF0aW9uLgpgYGB7ciB2b2xjYW5vX3Bsb3RfdG4sIGV2YWwgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQojIE1ha2UgYWxsIGRhdGEgdG8gZ3JleSBmaXJzdAp2b2xjYW5vX2NvbG9yX3RuID0gcmVwKCdncmF5JywgdGltZXMgPSBucm93KHFsZl90bl9oaXRzJHRhYmxlKSkKCiMgRm9yIHRob3NlIGRvd24tcmVndWxhdGVkIGdlbmVzIHdpdGggbW9yZSB0aGFuIDIgTEZDIGFuZCBwYXNzZXMgMC4wMSBGRFIgCiMgY29ycmVjdGlvbiB0aHJlc2hvbGQsIG1ha2UgaXQgYmx1ZQp2b2xjYW5vX2NvbG9yX3RuW3FsZl90bl9oaXRzJHRhYmxlJGxvZ0ZDIDwgMCAmCiAgICAgICAgICAgICAgICAgICAgICAgIHFsZl90bl9oaXRzJHRhYmxlJEZEUiA8IDAuMDEKICAgICAgICAgICAgICAgICAgICAgICYgYWJzKHFsZl90bl9oaXRzJHRhYmxlJGxvZ0ZDKSA+IDJdIDwtICdibHVlJwoKIyBGb3IgdXAtcmVndWxhdGVkIGdlbmVzIHdpdGggbW9yZSB0aGFuIDJMRkMgYW5kIHBhc3NlcyAwLjAxIEZEUgojIGNvcnJlY3Rpb24gdGhyZXNob2xkLCBtYWtlIGl0IHJlZAp2b2xjYW5vX2NvbG9yX3RuW3FsZl90bl9oaXRzJHRhYmxlJGxvZ0ZDID4gMCAmCiAgICAgICAgICAgICAgICAgICAgICAgIHFsZl90bl9oaXRzJHRhYmxlJEZEUiA8IDAuMDEgJgogICAgICAgICAgICAgICAgICAgICAgICBhYnMocWxmX3RuX2hpdHMkdGFibGUkbG9nRkMpID4gMl0gPC0gJ3JlZCcKCiMgUGxvdCB0aGUgdm9sY2FubyBwbG90CnBsb3QocWxmX3RuX2hpdHMkdGFibGUkbG9nRkMsCiAgICAgLWxvZyhxbGZfdG5faGl0cyR0YWJsZSRQVmFsdWUsIGJhc2U9MTApLAogICAgIGNvbCA9IHZvbGNhbm9fY29sb3JfdG4sCiAgICAgeGxhYiA9ICJsb2cyIGZvbGQgY2hhbmdlIiwKICAgICB5bGFiID0gIi1sb2cxMCBwIiwKICAgICBtYWluID0gIlZvbGNhbm8gcGxvdCBmb3IgVHVtb3IgdnMuIE5vcm1hbCBUaXNzdWVzIgopCgojIEFkZCB0aGUgbGVnZW5kCmxlZ2VuZCgidG9wbGVmdCIsIGxlZ2VuZD1jKCJEb3ducmVndWxhdGVkIGluIHR1bW9yIHRpc3N1ZXMiLCJVcHJlZ3VsYXRlZCBpbiB0dW1vciB0aXNzdWVzIiwgIk5vdCBzaWduaWZpY2FudCIpLAogICAgICAgZmlsbCA9IGMoImJsdWUiLCAicmVkIiwgImdyZXkiKSwgY2V4ID0gMC41KQoKIyBMYWJlbCBnZW5lcyB3aXRoIG92ZXIgNCBMRkMKdG5fc2lnIDwtIHdoaWNoKHFsZl90bl9oaXRzJHRhYmxlJGxvZ0ZDID4gNSB8IHFsZl90bl9oaXRzJHRhYmxlJGxvZ0ZDIDwgLTQpCnRleHQoeCA9IHFsZl90bl9oaXRzJHRhYmxlJGxvZ0ZDW3RuX3NpZ10gLCB5ID0gLWxvZzEwKHFsZl90bl9oaXRzJHRhYmxlJFBWYWx1ZVt0bl9zaWddKSwKICAgICBsYWJlbCA9IHJvd25hbWVzKHFsZl90bl9oaXRzJHRhYmxlKVt0bl9zaWddLCBjZXggPSAwLjUsIGFkaiA9IGMoMSwgTkEpLCBwb3MgPSAzKQoKYGBgCgo8YnI+ClRoZXJlIGlzIGV4dGVuc2l2ZSBudW1iZXIgb2YgdXByZWd1bGF0ZWQgZ2VuZXMgaW4gdHVtb3IgdGlzc3VlcyBjb21wYXJlZCB0byBub3JtYWwgdGlzc3Vlcywgd2l0aCB0aGUgaGlnaGVzdCBvZiBleGNlZWRpbmcgNiBMRkMgKGxvZzIgRm9sZCBDaGFuZ2UpLiBTZXZlcmFsIGdlbmVzIGFyZSBzaWduaWZpY2FudGx5IGRvd25yZWd1bGF0ZWQsIGhhdmluZyBtb3JlIHRoYW4gNCBMRkMuCmBgYHtyIHRuX3ZvbGNhbm9fZGlzcGxheSwgb3V0LndpZHRoID0gIjkwJSIsIGVjaG8gPSBGQUxTRSwgZmlnLmNhcD0iXFxsYWJlbHtmaWc6dm9sY2Fub190bn1GaWd1cmUgNC4gVm9sY2FubyBwbG90IGZvciB0aGUgdG9wIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyB0aGF0IHBhc3MgdGhlIDAuMDEgUC12YWx1ZSB0aHJlc2hvbGQgYW5kIGhhcyBhYnNvbHV0ZSBMRkMgb2YgbGFyZ2VyIHRoYW4gMi4gVXByZWd1bGF0ZWQgZ2VuZXMgd2l0aCBhYnNvbHV0ZSBsb2cgZm9sZCBjaGFuZ2Ugb3ZlciA1IGFuZCBkb3ducmVndWxhdGVkIGdlbmVzIHdpdGggYWJzb2x1dGUgTEZDIG92ZXIgNCBoYXZlIGJlZW4gbGFiZWxlZCBvdXQgdGhlIGNvcnJlc3BvbmRpbmcgSFVHTyBzeW1ib2xzLiIsIG1lc3NhZ2U9RkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWd1cmVzL3RuX3ZvbGNhbm8uanBnIiApCmBgYAo8YnI+CgoKCiMjIyBWb2xjYW5vIFBsb3QgKE1ldGFzdGFzZXMgdnMuIE5vcm1hbCkKV2UgYWxzbyBwbG90IHRoZSB2b2xjYW5vIHBsb3QgdG8gdmlzdWFsaXplIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIG9mIGdlbmVzIGZvciBtZXRhc3Rhc2VzIHZzLiBub3JtYWwgdGlzc3VlIHNhbXBsZXMuCmBgYHtyIHZvbGNhbm9fcGxvdF9tbiwgZXZhbCA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9CiMgTWFrZSBhbGwgZGF0YSB0byBncmV5IGZpcnN0CnZvbGNhbm9fY29sb3JfbW4gPSByZXAoJ2dyYXknLCB0aW1lcyA9IG5yb3cocWxmX21uX2hpdHMkdGFibGUpKQoKIyBGb3IgdGhvc2UgZG93bi1yZWd1bGF0ZWQgZ2VuZXMgd2l0aCBtb3JlIHRoYW4gMiBMRkMgYW5kIHBhc3NlcyAwLjAxIEZEUiAKIyBjb3JyZWN0aW9uIHRocmVzaG9sZCwgbWFrZSBpdCBibHVlCnZvbGNhbm9fY29sb3JfbW5bcWxmX21uX2hpdHMkdGFibGUkbG9nRkMgPCAwICYKICAgICAgICAgICAgICAgICAgICAgICAgcWxmX21uX2hpdHMkdGFibGUkRkRSIDwgMC4wMQogICAgICAgICAgICAgICAgICAgICAgJiBhYnMocWxmX21uX2hpdHMkdGFibGUkbG9nRkMpID4gMl0gPC0gJ2JsdWUnCgojIEZvciB1cC1yZWd1bGF0ZWQgZ2VuZXMgd2l0aCBtb3JlIHRoYW4gMkxGQyBhbmQgcGFzc2VzIDAuMDEgRkRSCiMgY29ycmVjdGlvbiB0aHJlc2hvbGQsIG1ha2UgaXQgcmVkCnZvbGNhbm9fY29sb3JfbW5bcWxmX21uX2hpdHMkdGFibGUkbG9nRkMgPiAwICYKICAgICAgICAgICAgICAgICAgICAgICAgcWxmX21uX2hpdHMkdGFibGUkRkRSIDwgMC4wMSAmCiAgICAgICAgICAgICAgICAgICAgICAgIGFicyhxbGZfbW5faGl0cyR0YWJsZSRsb2dGQykgPiAyXSA8LSAncmVkJwoKIyBQbG90IHRoZSB2b2xjYW5vIHBsb3QKcGxvdChxbGZfbW5faGl0cyR0YWJsZSRsb2dGQywKICAgICAtbG9nKHFsZl9tbl9oaXRzJHRhYmxlJFBWYWx1ZSwgYmFzZT0xMCksCiAgICAgY29sID0gdm9sY2Fub19jb2xvcl9tbiwKICAgICB4bGFiID0gImxvZzIgZm9sZCBjaGFuZ2UiLAogICAgIHlsYWIgPSAiLWxvZzEwIHAiLAogICAgIG1haW4gPSAiVm9sY2FubyBwbG90IGZvciBNZXRhc3Rhc2VzIHZzLiBOb3JtYWwgVGlzc3VlcyIKICAgICkKCgojIEFkZCB0aGUgbGVnZW5kCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQ9YygiRG93bnJlZ3VsYXRlZCBpbiB0dW1vciB0aXNzdWVzIiwiVXByZWd1bGF0ZWQgaW4gdHVtb3IgdGlzc3VlcyIsICJOb3Qgc2lnbmlmaWNhbnQiKSxmaWxsID0gYygiYmx1ZSIsICJyZWQiLCAiZ3JleSIpLCBjZXggPSAwLjUpCgojIExhYmVsIGdlbmVzIHdpdGggb3ZlciA1IExGQwptbl9zaWcgPC0gd2hpY2gocWxmX21uX2hpdHMkdGFibGUkbG9nRkMgPiA1IHwgcWxmX21uX2hpdHMkdGFibGUkbG9nRkMgPCAtNSkKdGV4dCh4ID0gcWxmX21uX2hpdHMkdGFibGUkbG9nRkNbbW5fc2lnXSAsIHkgPSAtbG9nMTAocWxmX21uX2hpdHMkdGFibGUkUFZhbHVlW21uX3NpZ10pLCBsYWJlbCA9IHJvd25hbWVzKHFsZl9tbl9oaXRzJHRhYmxlKVttbl9zaWddLCBjZXggPSAwLjUsIGFkaiA9IGMoMSwgTkEpLCBwb3MgPSAzKQoKYGBgCgo8YnI+CgpUaGVyZSBpcyBleHRlbnNpdmUgbnVtYmVyIG9mIHVwcmVndWxhdGVkIGFuZCBkb3ducmVndWxhdGVkIGdlbmVzIGluIG1ldGFzdGFzZXMgdGlzc3VlcyBjb21wYXJlZCB0byBub3JtYWwgdGlzc3Vlcywgd2l0aCB0aGUgaGlnaGVzdCBvZiBleGNlZWRpbmcgNSBMRkMuCmBgYHtyIG1uX3ZvbGNhbm9fZGlzcGxheSwgb3V0LndpZHRoID0gIjkwJSIsIGVjaG89RkFMU0UsIGZpZy5jYXA9IlxcbGFiZWx7ZmlnOnZvbGNhbm9fbW59RmlndXJlIDUuIFZvbGNhbm8gcGxvdCBmb3IgdGhlIHRvcCBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgdGhhdCBwYXNzIHRoZSAwLjAxIFAtdmFsdWUgdGhyZXNob2xkIGFuZCBoYXMgYWJzb2x1dGUgTEZDIG9mIGxhcmdlciB0aGFuIDIuIEdlbmVzIHdpdGggYWJzb2x1dGUgbG9nIGZvbGQgY2hhbmdlIG92ZXIgNSBoYXZlIGJlZW4gbGFiZWxlZCBvdXQgdGhlIGNvcnJlc3BvbmRpbmcgSFVHTyBzeW1ib2xzLiJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWd1cmVzL21uX3ZvbGNhbm8uanBnIiApCmBgYAo8YnI+CgoKIyMjIEhlYXRtYXAgKFR1bW9yIHZzLiBOb3JtYWwpCkluIG9yZGVyIHRvIGZpbmQgdGhlIG1vc3Qgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQsIHdlIHBpY2sgdGhlIGhpdHMgdGhhdCBwYXNzIGEgUC12YWx1ZSB0aHJlc2hvbGQgb2YgMC4wMSwgYW5kIGhhcyBhYnNvbHV0ZSB2YWx1ZSBvZiBMRkMgbGFyZ2VyIHRoYW4gMiBhcyB0aGUgdG9wIGhpdHMuCmBgYHtyIHRuX3RvcF9ERSwgbWVzc2FnZT1GQUxTRX0KIyBHZXQgdG9wIGhpdCBnZW5lcyBmb3IgVCB2cyBOCnRvcF9oaXRzX3RuIDwtIHJvd25hbWVzKHFsZl90bl9oaXRzKVtxbGZfdG5faGl0cyR0YWJsZSRQVmFsdWUgPCAwLjAxICYgYWJzKHFsZl90bl9oaXRzJHRhYmxlJGxvZ0ZDKSA+IDJdCmBgYAoKVGhlbiwgd2UgY2FsY3VsYXRlIHRoZWlyIGxvZzIgY291bnRzIHBlciBtaWxsaW9uIHZhbHVlLiBXZSBhZGQgMSB0byB0aGUgdmFsdWUgdG8gZWxpbWluYXRlIG1hdGhlbWF0aWNhbCBlcnJvciB3aGVuIHRoZSBjb3VudCBpcyAwLiBUaGlzIHRlY2huaXF1ZSBpcyBjb21tb25seSB1c2VkIGluIHByYWN0aXNlIHdoZW4gY2FsY3VsYXRpbmcgbG9nIHZhbHVlcy4KCmBgYHtyIGxvZ0NQTSwgbWVzc2FnZT1GQUxTRX0KIyBDYWxjdWxhdGUgbG9nQ1BNCmhtX21hdHJpeCA8LSBsb2cyKG5vcm1hbGl6ZWRfY291bnRzICsgMSkgIyBQbHVzIDEgdG8gZWxpbWluYXRlIGVycm9yIHdoZW4gdGhlIGNvdW50IGlzIDAuCmBgYAoKT2J0YWluIGRhdGEgZm9yIGVhY2ggY2F0ZWdvcnkKYGBge3J9CiMgT2J0YWluIHR1bW9yIGFuZCBub3JtYWwgdGlzc3VlIHNhbXBsZXMKdHVtb3IgPC0gZ3JlcCgiVCQiLCBjb2xuYW1lcyhobV9tYXRyaXgpLCB2YWx1ZT1UUlVFKQpub3JtYWwgPC0gZ3JlcCgiTiQiLCBjb2xuYW1lcyhobV9tYXRyaXgpLCB2YWx1ZT1UUlVFKQptZXRhc3Rhc2VzIDwtIGdyZXAoIk0kIiwgY29sbmFtZXMoaG1fbWF0cml4KSwgdmFsdWU9VFJVRSkKYGBgCgpTY2FsZSBoZWF0IG1hcCBtYXRyaXggYnkgcm93cy4KYGBge3IgdG5fc2NhbGUsIG1lc3NhZ2U9RkFMU0V9CiMgU2NhbGUgaGVhdCBtYXAgbWF0cml4IGJ5IHJvd3MKaG1fbWF0cml4X3RuIDwtIHQoc2NhbGUodChobV9tYXRyaXhbcm93bmFtZXMoaG1fbWF0cml4KSAlaW4lIHRvcF9oaXRzX3RuLCBjKHR1bW9yLCBub3JtYWwpXSkpKQpgYGAKClBpY2sgdGhlIGNvbG9yIHRvIGJlIHVzZWQgZm9yIHRoZSBwbG90LiBJZiBoZWF0bWFwIG9ubHkgY29udGFpbnMgbm9uLW5lZ2F0aXZlIHZhbHVlcywgd2Ugd2lsbCB1c2Ugb25seSB3aGl0ZSBhbmQgcmVkLCB3aGVyZSB3aGl0ZSBpbmRpY2F0ZXMgMCwgYW5kIHJlZCBpbmRpY2F0ZXMgcG9zaXRpdmUgdmFsdWVzLgoKT3RoZXJ3aXNlLCB3ZSB3aWxsIHVzZSBibHVlIHRvIHJlcHJlc2VudCBuZWdhdGl2ZSB2YWx1ZXMuCgpXZSBwbG90IHRoZSBoZWF0bWFwIHRvIHZpc3VhbGl6ZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBvZiBnZW5lcyBmb3IgbWV0YXN0YXNlcyB2cy4gbm9ybWFsIHRpc3N1ZSBzYW1wbGVzLgpgYGB7ciB0bl9oZWF0bWFwLCBldmFsPUZBTFNFLCBtZXNzYWdlID0gRkFMU0V9CiMgQ2hvb3NlIGNvbG9ycyB0byBiZSB1c2VkCmlmKG1pbihobV9tYXRyaXhfdG4pID09IDApewogICAgaGVhdG1hcF9jb2xvciA9IGNvbG9yUmFtcDIoYyggMCwgbWF4KGhtX21hdHJpeF90bikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoICJ3aGl0ZSIsICJyZWQiKSkKICB9IGVsc2UgewogICAgaGVhdG1hcF9jb2xvciA9IGNvbG9yUmFtcDIoYyhtaW4oaG1fbWF0cml4X3RuKSwgMCwKICAgICAgICAgIG1heChobV9tYXRyaXhfdG4pKSwgYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkKICB9CgojIENyZWF0ZSB0aGUgaGVhdG1hcCBmcm9tIHRoZSBnaXZlbiBtYXRyaXgsIHNob3dpbmcgdGhlIGRlbmRyb2dyYW0gZm9yIGJvdGggZ2VuZXMgYW5kIHNhbXBsZXMuCm5hbWUgPSAiRXhwcmVzc2lvbiBsZXZlbCIKaG1fdG4gPC0gSGVhdG1hcChhcy5tYXRyaXgoaG1fbWF0cml4X3RuKSwKICAgICAgc2hvd19yb3dfZGVuZCA9IFRSVUUsIHNob3dfY29sdW1uX2RlbmQgPSBUUlVFLAogICAgICBjb2wgPSBoZWF0bWFwX2NvbG9yLCBzaG93X2NvbHVtbl9uYW1lcyA9IFRSVUUsCiAgICAgIHNob3dfcm93X25hbWVzID0gRkFMU0UsIHNob3dfaGVhdG1hcF9sZWdlbmQgPSBUUlVFLAogICAgICBjb2x1bW5fbmFtZXNfZ3AgPSBncmlkOjpncGFyKGZvbnRzaXplID0gNiksCiAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdCh0aXRsZSA9IG5hbWUpKQoKZHJhdyhobV90biwKICAgY29sdW1uX3RpdGxlPSJUdW1vciB2cy4gTm9ybWFsIFRpc3N1ZSBIZWF0bWFwIGZvciBUb3AgREUgR2VuZXMiLAogICBjb2x1bW5fdGl0bGVfZ3A9Z3JpZDo6Z3Bhcihmb250c2l6ZT0xMikpCgoKYGBgCgpgYGB7ciB0bl9oZWF0bWFwX2Rpc3BsYXksIG91dC53aWR0aCA9ICI5MCUiLCBlY2hvID0gRkFMU0UsIGZpZy53aWR0aD03LGZpZy5oZWlnaHQ9NixmaWcuY2FwPSJcXGxhYmVse2ZpZzpoZWF0bWFwX3RufUZpZ3VyZSA2LiBIZWF0bWFwIGZvciB0aGUgdG9wIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyB0aGF0IHBhc3MgdGhlIDAuMDEgUC12YWx1ZSB0aHJlc2hvbGQuIFRoZXJlIGFyZSBjbGVhciBjbHVzdGVyaW5ncyBvZiBnZW5lcyB0aGF0IGFyZSB1cHJlZ3VsYXRlZCBpbiB0dW1vciB0aXNzdWVzLCB3aGlsZSBhcmUgZG93bnJlZ3VsYXRlZCBpbiBub3JtYWwgdGlzc3VlcywgaW5kaWNhdGluZyBjb25maWRlbnQgZXZpZGVuY2Ugb2YgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzLiIsIG1lc3NhZ2UgPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImZpZ3VyZXMvdG5faGVhdG1hcC5qcGciICkKYGBgCgoKIyMjIEhlYXRtYXAgKE1ldGFzdGFzZXMgdnMuIE5vcm1hbCkKTm93IHdlIGNhbiBhbHNvIHBsb3QgaGVhdG1hcCBmb3IgTWV0YXN0YXNlcyB2cy4gTm9ybWFsIGNvbXBhcmlzb24sIHdpdGggc2FtZSBzdGVwcyBhcyBhYm92ZS4KYGBge3IgbW5fdG9wX0RFLCBtZXNzYWdlPUZBTFNFfQojIEdldCB0b3AgaGl0IGdlbmVzIGZvciBNIHZzIE4KdG9wX2hpdHNfbW4gPC0gcm93bmFtZXMocWxmX21uX2hpdHMpW3FsZl9tbl9oaXRzJHRhYmxlJFBWYWx1ZSA8IDAuMDEgJiBhYnMocWxmX21uX2hpdHMkdGFibGUkbG9nRkMpID4gMl0KYGBgCgpgYGB7ciBtbl9zY2FsZSwgbWVzc2FnZT1GQUxTRX0KIyBTY2FsZSBoZWF0IG1hcCBtYXRyaXggYnkgcm93cwpobV9tYXRyaXhfbW4gPC0gdChzY2FsZSh0KGhtX21hdHJpeFtyb3duYW1lcyhobV9tYXRyaXgpICVpbiUgdG9wX2hpdHNfbW4sIGMobWV0YXN0YXNlcywgbm9ybWFsKV0pKSkKYGBgCgpgYGB7ciBtbl9oZWF0bWFwLCBldmFsID0gRkFMU0V9CiMgQ2hvb3NlIGNvbG9ycyB0byBiZSB1c2VkCmlmKG1pbihobV9tYXRyaXhfbW4pID09IDApewogICAgaGVhdG1hcF9jb2xvciA9IGNvbG9yUmFtcDIoYyggMCwgbWF4KGhtX21hdHJpeF9tbikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoICJ3aGl0ZSIsICJyZWQiKSkKICB9IGVsc2UgewogICAgaGVhdG1hcF9jb2xvciA9IGNvbG9yUmFtcDIoYyhtaW4oaG1fbWF0cml4X21uKSwgMCwKICAgICAgICAgIG1heChobV9tYXRyaXhfbW4pKSwgYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkKICB9CgojIENyZWF0ZSB0aGUgaGVhdG1hcCBmcm9tIHRoZSBnaXZlbiBtYXRyaXgsIHNob3dpbmcgdGhlIGRlbmRyb2dyYW0gZm9yIGJvdGggZ2VuZXMgYW5kIHNhbXBsZXMuCmhtX21uIDwtIEhlYXRtYXAoYXMubWF0cml4KGhtX21hdHJpeF9tbiksCiAgICAgIHNob3dfcm93X2RlbmQgPSBUUlVFLCBzaG93X2NvbHVtbl9kZW5kID0gVFJVRSwKICAgICAgY29sID0gaGVhdG1hcF9jb2xvciwgc2hvd19jb2x1bW5fbmFtZXMgPSBUUlVFLAogICAgICBzaG93X3Jvd19uYW1lcyA9IEZBTFNFLCBzaG93X2hlYXRtYXBfbGVnZW5kID0gVFJVRSwKICAgICAgY29sdW1uX25hbWVzX2dwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDYpLAogICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QodGl0bGUgPSBuYW1lKSkKCmRyYXcoaG1fbW4sCiAgIGNvbHVtbl90aXRsZT0iTWV0YXN0YXNlcyB2cyBOb3JtYWwgVGlzc3VlIEhlYXRtYXAgZm9yIFRvcCBERSBHZW5lcyIsCiAgIGNvbHVtbl90aXRsZV9ncD1ncmlkOjpncGFyKGZvbnRzaXplPTEyKSkKYGBgCgpgYGB7ciBtbl9oZWF0bWFwX2Rpc3BsYXksIG91dC53aWR0aCA9ICI5MCUiLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLndpZHRoPTcsZmlnLmhlaWdodD02LGZpZy5jYXA9IlxcbGFiZWx7ZmlnOmhlYXRtYXBfbW59RmlndXJlIDcuIEhlYXRtYXAgZm9yIHRoZSB0b3AgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIHRoYXQgcGFzcyB0aGUgMC4wMSBQLXZhbHVlIHRocmVzaG9sZC4gVGhlcmUgYXJlIGNsZWFyIGNsdXN0ZXJpbmdzIG9mIGdlbmVzIHRoYXQgYXJlIHVwcmVndWxhdGVkIGluIG1ldGFzdGFzZXMgdGlzc3Vlcywgd2hpbGUgYXJlIGRvd25yZWd1bGF0ZWQgaW4gbm9ybWFsIHRpc3N1ZXMsIGluZGljYXRpbmcgY29uZmlkZW50IGV2aWRlbmNlIG9mIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcy4ifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiZmlndXJlcy9tbl9oZWF0bWFwLmpwZyIgKQpgYGAKCgojIyBEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbiBBbmFseXNpcyBEaXNjdXNzaW9uCgojIyMgMS4gQ2FsY3VsYXRlIHAtdmFsdWVzIGZvciBlYWNoIG9mIHRoZSBnZW5lcyBpbiB5b3VyIGV4cHJlc3Npb24gc2V0LiBIb3cgbWFueSBnZW5lcyB3ZXJlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkPyBXaGF0IHRocmVzaG9sZHMgZGlkIHlvdSB1c2UgYW5kIHdoeT8KCkF0IGZpcnN0LCBJIGVtcGxveWVkIHRoZSBjb21tb25seSB1c2VkIHAtdmFsdWUgb2YgMC4wNSwgcmVzdWx0aW5nIGluIDcxNDUgZ2VuZXMgZm9yIHRoZSB0dW1vciB2cy4gbm9ybWFsIHRpc3N1ZSBhbmFseXNpcywgYW5kIDg2MzQgZ2VuZXMgZm9yIHRoZSBtZXRhc3Rhc2VzIHZzLiBub3JtYWwgdGlzc3VlIGFuYWx5c2lzLCBiZWZvcmUgbXVsdGlwbGUgaHlwb3RoZXNpcyB0ZXN0aW5nIGNvcnJlY3Rpb25zLiBIb3dldmVyLCB0aGlzIHdhcyBhbiBleHRlbnNpdmUgc2V0IG9mIGdlbmVzLCBwcm9tcHRpbmcgdXMgdG8gYWx0ZXIgdGhlIHAtdmFsdWUgdGhyZXNob2xkIHRvIDAuMDEsIGFuZCBGRFIgdGhyZXNob2xkIGFsc28gdG8gMC4wMSwgdG8gcmVzdHJpY3QgdGhlIG51bWJlciBvZiBnZW5lcyB0byBiZSBpbmNsdWRlZC4gQWRkaXRpb25hbGx5LCB3ZSBpbXBvc2VkIGEgY3JpdGVyaW9uIHRoYXQgYSBnZW5lIHNob3VsZCBoYXZlIGFuIGFic29sdXRlIGxvZzIgZm9sZCBjaGFuZ2Ugb2YgYXQgbGVhc3QgMi4gVGhpcyBlbnN1cmVkIHRoYXQgd2Ugb25seSBvYnRhaW5lZCBnZW5lcyB3aXRoIHNpZ25pZmljYW50IGRpZmZlcmVudGlhbCBleHByZXNzaW9uLCB3aGljaCB3ZSBiZWxpZXZlZCB0byBiZSBtZWFuaW5nZnVsIGFuZCBlc3NlbnRpYWwgZm9yIGZ1cnRoZXIgYW5hbHlzaXMuCgojIyMgMi4gTXVsdGlwbGUgaHlwb3RoZXNpcyB0ZXN0aW5nIC0gY29ycmVjdCB5b3VyIHAtdmFsdWVzIHVzaW5nIGEgbXVsdGlwbGUgaHlwb3RoZXNpcyBjb3JyZWN0aW9uIG1ldGhvZC4gV2hpY2ggbWV0aG9kIGRpZCB5b3UgdXNlPyBBbmQgV2h5PyBIb3cgbWFueSBnZW5lcyBwYXNzZWQgY29ycmVjdGlvbj8KClRoZSB0d28gcHJpbWFyeSBhcHByb2FjaGVzIGZvciBjb250cm9sbGluZyBmYWxzZSBkaXNjb3ZlcnkgcmF0ZSBhcmUgQm9uZmVycm9uaSBhbmQgQmVuamFtaW5pLUhvY2hiZXJnIGNvcnJlY3Rpb25zLCBhbmQgd2UgZW1wbG95ZWQgdGhlIEJlbmphbWluaS1Ib2NoYmVyZyBtZXRob2QgZm9yIG11bHRpcGxlIGh5cG90aGVzaXMgdGVzdGluZyBjb3JyZWN0aW9uLiBPdXIgb2JqZWN0aXZlIHdhcyB0byBpZGVudGlmeSBzaWduaWZpY2FudCBoaXRzIHdpdGhvdXQgb21pdHRpbmcgbWVhbmluZ2Z1bCBvbmVzLiBCb25mZXJyb25pIG1ldGhvZCBpcyB1c2VmdWwgd2hlbiB0aGUgbnVtYmVyIG9mIHRlc3RzIGlzIHNtYWxsIGFuZCB3aGVuIHRoZSB0ZXN0cyBhcmUgaW5kZXBlbmRlbnQgb2YgZWFjaCBvdGhlciwgYnV0IGl0IGJlY29tZXMgb3Zlcmx5IHN0cmluZ2VudCBhbmQgaW1wcmFjdGljYWwgd2hlbiB0aGUgbnVtYmVyIG9mIHRlc3RzIGlzIGxhcmdlIG9yIHdoZW4gdGhlIHRlc3RzIGFyZSBjb3JyZWxhdGVkLiBTaW5jZSB3ZSBhcmUgZGVhbGluZyB3aXRoIGEgbGFyZ2UgZGF0YXNldCB3aXRoIG92ZXIgODAgc2FtcGxlcywgQm9uZmVycm9uaSBpcyBub3QgZGVzaXJhYmxlIGZvciBvdXIgcHVycG9zZS4gVGhlcmVmb3JlLCB3ZSBvcHRlZCBmb3IgQmVuamFtaW5pLUhvY2hiZXJnIGNvcnJlY3Rpb24sIHdoaWNoIHByb3ZpZGVkIGEgbW9yZSBjb21wcmVoZW5zaXZlIHNldCBvZiBnZW5lcyBmb3IgZG93bnN0cmVhbSBhbmFseXNpcy4gRm9sbG93aW5nIHRoaXMgY29ycmVjdGlvbiwgd2UgZm91bmQgdGhhdCB0aGUgdHVtb3IgdnMuIG5vcm1hbCB0aXNzdWUgYW5hbHlzaXMgeWllbGRlZCAzODkzIGdlbmVzLCBhbmQgdGhlIG1ldGFzdGFzZXMgdnMuIG5vcm1hbCB0aXNzdWUgYW5hbHlzaXMgeWllbGRlZCA1NDc3IGdlbmVzIHRoYXQgcGFzc2VkIHRoZSBjb3JyZWN0aW9uLgoKIyMjIDMuIFNob3cgdGhlIGFtb3VudCBvZiBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgdXNpbmcgYW4gTUEgUGxvdCBvciBhIFZvbGNhbm8gcGxvdC4gSGlnaGxpZ2h0IGdlbmVzIG9mIGludGVyZXN0LgoKVm9sY2FubyBwbG90cyBmb3IgYm90aCBUdW1vciB2cy4gTm9ybWFsIGFuZCBNZXRhc3Rhc2VzIHZzLiBOb3JtYWwgZGF0YXNldHMgYXJlIHNob3duIGFib3ZlLiBUaGUgbW9zdCBzaWduaWZpY2FudGx5IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBhcmUgbGFiZWxlZCBvdXQgYnkgdGhlaXIgSFVHTyBzeW1ib2xzIGluIHRoZSBmaWd1cmVzLgoKIyMjIDQuIFZpc3VhbGl6ZSB5b3VyIHRvcCBoaXRzIHVzaW5nIGEgaGVhdG1hcC4gRG8geW91ciBjb25kaXRpb25zIGNsdXN0ZXIgdG9nZXRoZXI/IEV4cGxhaW4gd2h5IG9yIHdoeSBub3QuCgpUaGVyZSBhcmUgY2xlYXIgY2x1c3RlcmluZ3Mgd2l0aGluIGNvbmRpdGlvbnMsIGFzIHNob3duIGluIHRoZSBncmFwaCByZXByZXNlbnRlZCBpbiByZWQgYW5kIGJsdWUuIFRoaXMgc3VnZ2VzdHMgdGhhdCB0aGUgdHVtb3IgdGlzc3VlcyBhbmQgbWV0YXN0YXNlcyB0aXNzdWVzIGRvIGhhdmUgZ2VuZXMgdGhhdCBhcmUgaGlnaGx5IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBjb21wYXJlZCB0byBub3JtYWwgdGlzc3Vlcy4gCgoKIyBUaHJlc2hvbGRlZCBPdmVycmVwcmVzZW50YXRpb24gQW5hbHlzaXMgdXNpbmcgZzpQcm9maWxlcgoKCkZvciB0aGUgZmluYWwgcGFydCBvZiB0aGlzIGFzc2lnbm1lbnQsIHdlIHdpbGwgcGVyZm9ybSBhIHRocmVzaG9sZGVkIG92ZXJyZXByZXNlbnRhdGlvbiBhbmFseXNpcyB1c2luZyBnOlByb2ZpbGVyLiBJbiB0aGUgcHJldmlvdXMgc2VjdGlvbiwgd2UgaGF2ZSBjb21waWxlZCBhIGxpc3Qgb2YgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzLiBIZXJlLCB3ZSB3YW50IHRvIGZ1cnRoZXIgZGl2aWRlIHRoZW0gaW50byB1cHJlZ3VsYXRlZCBhbmQgZG93bnJlZ3VsYXRlZCBnZW5lcy4KCiMjIFR1bW9yIHZzLiBOb3JtYWwgVGlzc3VlCkZpcnN0LCB3ZSBvYnRhaW4gdGhlIHVwcmVndWxhdGVkIGFuZCBkb3ducmVndWxhdGVkIGdlbmVzIGZyb20gdGhlIHR1bW9yIHZzLiBub3JtYWwgdGlzc3VlIGRhdGFzZXQuCmBgYHtyIHRuX3NwbGl0X3VwZG93bnJlZ3VsYXRlZH0KdXByZWd1bGF0ZWRfdG4gPC0gcWxmX3RuX2hpdHNbcWxmX3RuX2hpdHMkdGFibGUkbG9nRkMgPiAwICYgcWxmX3RuX2hpdHMkdGFibGUkUFZhbHVlIDwgMC4wMSwgXQpkb3ducmVndWxhdGVkX3RuIDwtIHFsZl90bl9oaXRzW3FsZl90bl9oaXRzJHRhYmxlJGxvZ0ZDIDwgMCAmIHFsZl90bl9oaXRzJHRhYmxlJFBWYWx1ZSA8IDAuMDEsIF0KYGBgCgpXZSB1c2UgdGhlIFIgcGFja2FnZSBmb3IgZzpQcm9maWxlciB0byBwZXJmb3JtIHRoZSBnZW5lIGVucmljaG1lbnQgYW5hbHlzaXMuIEZvciBjb3JyZWN0aW9uLCB3ZSB1c2VkIEZEUiBhcyBpdCBpcyBsZXNzIHN0cmluZ2VudCB0aGFuIEJvbmZlcnJvbmkgYW5kIGlzIGludHJvZHVjZWQgdG8gYmUgdGhlIHByZWZlcnJlZCBjb3JyZWN0aW9uIG1ldGhvZCBpbiBjbGFzcy4gV2UgdXNlZCBHTyBCaW9sb2dpY2FsIFByb2Nlc3MsIEdPIE1vbGVjdWxhciBGdW5jdGlvbiwgYW5kIFdQIGFzIHRob3NlIGFyZSB0aGUgb25lcyB1c2VkIHByZXZpb3VzbHkgaW4gSm91cm5hbCBlbnRyeSBhc3NpZ25tZW50cywgd2hpY2ggd2UgYXJlIG1vcmUgZmFtaWxpYXIgd2l0aC4KClRoZW4sIHdlIHBlcmZvcm0gYW5hbHlzaXMgc2VwYXJhdGVseSBmb3IgdXAtcmVndWxhdGVkIGdlbmVzIGFuZCBkb3duLXJlZ3VsYXRlZCBnZW5lcy4KCiMjIyBVcHJlZ3VsYXRlZCBHZW5lcwpUbyBvYnRhaW4gdGhlIHRlcm1zIHRoZXNlIGdlbmVzIGFyZSBpbnZvbHZlZCBpbiwgd2UgdXNlIHRoZSBfXyoqZ29zdCoqX18gZnVuY3Rpb24gZnJvbSBnUHJvZmlsZXIyIHBhY2thZ2UuCmBgYHtyIHRuX2dwcm9maWxlcl91cCwgbWVzc2FnZT1GQUxTRX0KIyBPYnRhaW4gdG9wIHRlcm1zCnRuX3VwX3RvcF90ZXJtc19hbGwgPC0gZ3Byb2ZpbGVyMjo6Z29zdChxdWVyeSA9IHJvd25hbWVzKHVwcmVndWxhdGVkX3RuKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICJoc2FwaWVucyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjbHVkZV9pZWEgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ycmVjdGlvbl9tZXRob2QgPSAiZmRyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZXMgPSBjKCJHTzpCUCIsICJSRUFDIiwgIldQIikpCiMgTGltaXQgdGVybSBzaXplIGZyb20gMSB0byA1MDAKdG5fdXBfdG9wX3Rlcm1zIDwtIGRhdGEuZnJhbWUoCiAgdGVybV9uYW1lID0gdG5fdXBfdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9uYW1lW3RuX3VwX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fc2l6ZSA8IDUwMCAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG5fdXBfdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9zaXplID4gMV0sCiAgdGVybV9pZCA9IHRuX3VwX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1faWRbdG5fdXBfdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9zaXplIDwgNTAwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRuX3VwX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fc2l6ZSA+IDFdLAogIHNvdXJjZSA9IHRuX3VwX3RvcF90ZXJtc19hbGwkcmVzdWx0JHNvdXJjZVt0bl91cF90b3BfdGVybXNfYWxsJHJlc3VsdCR0ZXJtX3NpemUgPCA1MDAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRuX3VwX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fc2l6ZSA+IDFdCikKCmtuaXRyOjprYWJsZShoZWFkKHRuX3VwX3RvcF90ZXJtcywgMTApLCBmb3JtYXQgPSAiaHRtbCIpCmBgYAoKRm9yIGNvbnRleHQsIGxldCdzIGV4YW1pbmUgdGhlIHRvcCB0ZXJtIGZyb20gZWFjaCBkYXRhIHNvdXJjZS4KCmBgYHtyIHRuX3VwX3RvcF90ZXJtX3Blcl9jYXRlZ29yeSwgbWVzc2FnZT1GQUxTRX0Ka25pdHI6OmthYmxlKHJiaW5kKHRuX3VwX3RvcF90ZXJtc1t0bl91cF90b3BfdGVybXMkc291cmNlID09ICJHTzpCUCIsXVsxLF0sCiAgICAgICAgICAgICAgICAgICB0bl91cF90b3BfdGVybXNbdG5fdXBfdG9wX3Rlcm1zJHNvdXJjZSA9PSAiUkVBQyIsXVsxLF0sCiAgICAgICAgICAgICAgICAgICB0bl91cF90b3BfdGVybXNbdG5fdXBfdG9wX3Rlcm1zJHNvdXJjZSA9PSAiV1AiLF1bMSxdKSwKICAgICAgICAgICAgIGZvcm1hdCA9ICJodG1sIikKYGBgCkdlbmVyYXRlIGEgTWFuaGF0dGFuIHBsb3QgdG8gdmlzdWFsaXplIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHRvcCB0ZXJtcyBmcm9tIGVhY2ggZGF0YSBzb3VyY2UuCgpgYGB7ciB0bl91cF9kaXN0X3Bsb3QsIGZpZy5jYXA9IkZpZ3VyZSA4LiBNYW5oYXR0YW4gcGxvdCBkaXNwbGF5aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHRvcCB0ZXJtcyBmcm9tIGVhY2ggZGF0YSBzb3VyY2UgZm9yIHVwcmVndWxhdGVkIGdlbmVzIGluIHR1bW9yIHZzLiBub3JtYWwgY29tcGFyaXNvbi4gVGhlcmUgYXJlIGV4dGVuc2l2ZSBudW1iZXJzIG9mIEdQOkJQIHRlcm1zIGNvcGFyZWQgdG8gUkVBQyBhbmQgV1AsIGFuZCB0ZXJtcyBzdWNoIGFzIGNlbGwgYWRoZXNpb24sIGFuYXRvbWljYWwgc3RydWN0dXJlIG1vcnBob2dlbmVzaXMgYW5kIGFuYXRvbWljYWwgc3RydWN0dXJlIGRldmVsb3BtZW50IGFyZSBleGNlZWRpbmcgMTYgLWxvZzEwIGNvcnJlY3Rpb24gdGhyZXNob2xkLiJ9Cmdwcm9maWxlcjI6Omdvc3RwbG90KHRuX3VwX3RvcF90ZXJtc19hbGwpICU+JSBwbG90bHk6OmxheW91dCh0aXRsZSA9ICJNYW5oYXR0YW4gcGxvdCBmb3IgVXByZWd1bGF0ZWQgZ2VuZXMgKFR1bW9yIHZzLiBOb3JtYWwpIiwgZm9udCA9IGxpc3Qoc2l6ZSA9IDEwKSkKYGBgCk51bWJlciBvZiB0ZXJtczoKYGBge3IgdG5fY291bnRfdXBfdG9wX3Rlcm1zLCBtZXNzYWdlPUZBTFNFfQpsZW5ndGgodG5fdXBfdG9wX3Rlcm1zJHRlcm1fbmFtZSkKYGBgCgojIyMgRG93bnJlZ3VsYXRlZCBHZW5lcwoKV2UgZG8gdGhlIHNhbWUgZm9yIHRoZSBkb3ducmVndWFsdGVkIGdlbmVzLgoKYGBge3IgdG5fZ3Byb2ZpbGVyX2Rvd24sIG1lc3NhZ2U9RkFMU0V9CnRuX2Rvd25fdG9wX3Rlcm1zX2FsbCA8LSBncHJvZmlsZXIyOjpnb3N0KHF1ZXJ5ID0gcm93bmFtZXMoZG93bnJlZ3VsYXRlZF90biksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAiaHNhcGllbnMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2x1ZGVfaWVhID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcnJlY3Rpb25fbWV0aG9kID0gImZkciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2VzID0gYygiR086QlAiLCAiUkVBQyIsICJXUCIpKQoKdG5fZG93bl90b3BfdGVybXMgPC0gZGF0YS5mcmFtZSgKICB0ZXJtX25hbWUgPSB0bl9kb3duX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fbmFtZVt0bl9kb3duX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fc2l6ZSA8IDUwMCAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0bl9kb3duX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fc2l6ZSA+IDFdLAogIHRlcm1faWQgPSB0bl9kb3duX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1faWRbdG5fZG93bl90b3BfdGVybXNfYWxsJHJlc3VsdCR0ZXJtX3NpemUgPCA1MDAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0bl9kb3duX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fc2l6ZSA+IDFdLAogIHNvdXJjZSA9IHRuX2Rvd25fdG9wX3Rlcm1zX2FsbCRyZXN1bHQkc291cmNlW3RuX2Rvd25fdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9zaXplIDwgNTAwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRuX2Rvd25fdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9zaXplID4gMV0KKQoKa25pdHI6OmthYmxlKGhlYWQodG5fZG93bl90b3BfdGVybXMsIDEwKSxmb3JtYXQgPSAiaHRtbCIpCmBgYAo8YnI+ClRvcCB0ZXJtcyBmcm9tIHRoZSBkYXRhIHNvdXJjZXM6CmBgYHtyIHRuX2Rvd25fdG9wX3Rlcm1fcGVyX2NhdGVnb3J5LCBtZXNzYWdlPUZBTFNFfQprbml0cjo6a2FibGUocmJpbmQodG5fZG93bl90b3BfdGVybXNbdG5fZG93bl90b3BfdGVybXMkc291cmNlID09ICJHTzpCUCIsXVsxLF0sCiAgICAgICAgICAgICAgICAgICB0bl9kb3duX3RvcF90ZXJtc1t0bl9kb3duX3RvcF90ZXJtcyRzb3VyY2UgPT0gIlJFQUMiLF1bMSxdLAogICAgICAgICAgICAgICAgICAgdG5fZG93bl90b3BfdGVybXNbdG5fZG93bl90b3BfdGVybXMkc291cmNlID09ICJXUCIsXVsxLF0pLAogICAgICAgICAgICAgZm9ybWF0ID0gImh0bWwiKQpgYGAKUGxvdCB0aGUgTWFuaGF0dGFuIHBsb3QgdG8gdmlzdWFsaXplIGRpc3RyaWJ1dGlvbiBvZiB0ZXJtcyBmcm9tIGVhY2ggZGF0YSBzb3VyY2UgZm9yIGRvd25yZWd1bGF0ZWQgZ2VuZXMuCgpgYGB7ciB0bl9kb3duX2Rpc3RfcGxvdCwgZmlnLmNhcD0iRmlndXJlIDkuIE1hbmhhdHRhbiBwbG90IGRpc3BsYXlpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgdG9wIHRlcm1zIGZyb20gZWFjaCBkYXRhIHNvdXJjZSBmb3IgZG93bnJlZ3VsYXRlZCBnZW5lcyBpbiB0dW1vciB2cy4gbm9ybWFsIGNvbXBhcmlzb24uIFRoZXJlIGFyZSBsZXNzIHRlcm1zIGluY2x1ZGVkIGNvbXBhcmluZyB0byB0aGUgdXByZWd1bGF0ZWQgZ2VuZXMuIn0KZ3Byb2ZpbGVyMjo6Z29zdHBsb3QodG5fZG93bl90b3BfdGVybXNfYWxsKSAlPiUgCiAgcGxvdGx5OjpsYXlvdXQodGl0bGUgPSAiTWFuaGF0dGFuIHBsb3QgZm9yIERvd25yZWd1bGF0ZWQgZ2VuZXMgKFR1bW9yIHZzLiBOb3JtYWwpIiwgZm9udCA9IGxpc3Qoc2l6ZSA9IDEwKSkKYGBgCk51bWJlciBvZiB0ZXJtcwpgYGB7ciB0bl9jb3VudF9kb3duX3RvcF90ZXJtcywgbWVzc2FnZT1GQUxTRX0KbGVuZ3RoKHRuX2Rvd25fdG9wX3Rlcm1zJHRlcm1fbmFtZSkKYGBgCgojIyMgQWxsIERpZmZlcmVudGlhbGx5IEV4cHJlc3NlZCBHZW5lcwoKRmluYWxseSwgd2UgYW5hbHl6ZSBmb3IgYWxsIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyAoaS5lLiBib3RoIHVwLXJlZ3VsYXRlZCBhbmQgZG93bi1yZWd1bGF0ZWQgZ2VuZXMgYXMgYSB3aG9sZSkuCgpgYGB7ciB0bl9ncHJvZmlsZXJfb3ZlcmFsbCwgbWVzc2FnZT1GQUxTRX0KdG5fdG9wX3Rlcm1zX2FsbCA8LSBncHJvZmlsZXIyOjpnb3N0KHF1ZXJ5ID0gcm93bmFtZXMocWxmX3RuX2hpdHMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gImhzYXBpZW5zIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGNsdWRlX2llYSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JyZWN0aW9uX21ldGhvZCA9ICJmZHIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc291cmNlcyA9IGMoIkdPOkJQIiwgIlJFQUMiLCAiV1AiKSkKCnRuX3RvcF90ZXJtcyA8LSBkYXRhLmZyYW1lKAogIHRlcm1fbmFtZSA9IHRuX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fbmFtZVt0bl90b3BfdGVybXNfYWxsJHJlc3VsdCR0ZXJtX3NpemUgPCA1MDAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRuX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fc2l6ZSA+IDFdLAogIHRlcm1faWQgPSB0bl90b3BfdGVybXNfYWxsJHJlc3VsdCR0ZXJtX2lkW3RuX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fc2l6ZSA8IDUwMCAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0bl90b3BfdGVybXNfYWxsJHJlc3VsdCR0ZXJtX3NpemUgPiAxXSwKICBzb3VyY2UgPSB0bl90b3BfdGVybXNfYWxsJHJlc3VsdCRzb3VyY2VbdG5fdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9zaXplIDwgNTAwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0bl90b3BfdGVybXNfYWxsJHJlc3VsdCR0ZXJtX3NpemUgPiAxXQopCgprbml0cjo6a2FibGUoaGVhZCh0bl90b3BfdGVybXMsIDEwKSwgZm9ybWF0ID0gImh0bWwiKQpgYGAKPGJyPgpUb3AgdGVybXMgZnJvbSB0aGUgZGF0YSBzb3VyY2VzOgoKYGBge3IgdG5fdG9wX3Rlcm1fcGVyX2NhdGVnb3J5LCBtZXNzYWdlPUZBTFNFfQprbml0cjo6a2FibGUocmJpbmQodG5fdG9wX3Rlcm1zW3RuX3RvcF90ZXJtcyRzb3VyY2UgPT0gIkdPOkJQIixdWzEsXSwKICAgICAgICAgICAgICAgICAgIHRuX3RvcF90ZXJtc1t0bl90b3BfdGVybXMkc291cmNlID09ICJSRUFDIixdWzEsXSwKICAgICAgICAgICAgICAgICAgIHRuX3RvcF90ZXJtc1t0bl90b3BfdGVybXMkc291cmNlID09ICJXUCIsXVsxLF0pLAogICAgICAgICAgICAgZm9ybWF0ID0gImh0bWwiKQpgYGAKCgpgYGB7ciB0bl9hbGxfZGlzdF9wbG90LCBmaWcuY2FwPSJGaWd1cmUgMTAuIE1hbmhhdHRhbiBwbG90IGRpc3BsYXlpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgdG9wIHRlcm1zIGZyb20gZWFjaCBkYXRhIHNvdXJjZSBmb3IgYWxsIGdlbmVzIGluIHR1bW9yIHZzLiBub3JtYWwgY29tcGFyaXNvbi4gVGhlcmUgYXJlIG1hbnkgdGVybXMgZXhjZWVkaW5nIDE2IGFkanVzdGVkIHAgdmFsbHVlLCBpbmRpY2F0aW5nIHZlcnkgc3Ryb25nIGVucmljaG1lbnQgc2lnbmFsLiJ9Cmdwcm9maWxlcjI6Omdvc3RwbG90KHRuX3RvcF90ZXJtc19hbGwpICU+JSBwbG90bHk6OmxheW91dCh0aXRsZSA9ICJNYW5oYXR0YW4gcGxvdCBmb3IgQWxsIERFIGdlbmVzIChUdW1vciB2cy4gTm9ybWFsKSIsIGZvbnQgPSBsaXN0KHNpemUgPSAxMCkpCmBgYAoKVGhlcmUgYSB0b3RhbCBvZiAxNDQ3IHRlcm1zOgpgYGB7ciB0bl9jb3VudF90b3BfdGVybXMsIG1lc3NhZ2U9RkFMU0V9Cmxlbmd0aCh0bl90b3BfdGVybXMkdGVybV9uYW1lKQpgYGAKCgoKIyMgTWV0YXN0YXNlcyB2cy4gTm9ybWFsIFRpc3N1ZQoKQWdhaW4sIHdlIHBlcmZvcm0gdGhlIGFuYWx5c2lzIGZvciBNZXRhc3Rhc2VzIHZzLiBOb3JtYWwgdGlzc3VlIGNvbXBhcmlzb24uIEZpcnN0LCB3ZSBvYnRhaW4gdGhlIHVwLXJlZ3VsYXRlZCBnZW5lcyBhbmQgZG93bi1yZWd1bGF0ZWQgZ2VuZXMgc2VwYXJhdGVseS4KYGBge3IgbW5fc3BsaXRfdXBkb3ducmVndWxhdGVkfQp1cHJlZ3VsYXRlZF9tbiA8LSBxbGZfbW5faGl0c1txbGZfbW5faGl0cyR0YWJsZSRsb2dGQyA+IDAgJiBxbGZfbW5faGl0cyR0YWJsZSRQVmFsdWUgPCAwLjAxLCBdCmRvd25yZWd1bGF0ZWRfbW4gPC0gcWxmX21uX2hpdHNbcWxmX21uX2hpdHMkdGFibGUkbG9nRkMgPCAwICYgcWxmX21uX2hpdHMkdGFibGUkUFZhbHVlIDwgMC4wMSwgXQpgYGAKCiMjIyBVcHJlZ3VsYXRlZCBHZW5lcwpPYnRhaW4gYWxsIHRlcm1zIGludm9sdmVkIGZvciB1cC1yZWd1bGF0ZWQgZ2VuZXMgdXNpbmcgR086QlAsIFJFQUMgYW5kIFdQIGRhdGEgc291cmNlLgpgYGB7ciBtbl9ncHJvZmlsZXJfdXAsIG1lc3NhZ2U9RkFMU0V9Cm1uX3VwX3RvcF90ZXJtc19hbGwgPC0gZ3Byb2ZpbGVyMjo6Z29zdChxdWVyeSA9IHJvd25hbWVzKHVwcmVndWxhdGVkX21uKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICJoc2FwaWVucyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjbHVkZV9pZWEgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ycmVjdGlvbl9tZXRob2QgPSAiZmRyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZXMgPSBjKCJHTzpCUCIsICJSRUFDIiwgIldQIikpCgptbl91cF90b3BfdGVybXMgPC0gZGF0YS5mcmFtZSgKICB0ZXJtX25hbWUgPSBtbl91cF90b3BfdGVybXNfYWxsJHJlc3VsdCR0ZXJtX25hbWVbbW5fdXBfdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9zaXplIDwgNTAwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtbl91cF90b3BfdGVybXNfYWxsJHJlc3VsdCR0ZXJtX3NpemUgPiAxXSwKICB0ZXJtX2lkID0gbW5fdXBfdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9pZFttbl91cF90b3BfdGVybXNfYWxsJHJlc3VsdCR0ZXJtX3NpemUgPCA1MDAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW5fdXBfdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9zaXplID4gMV0sCiAgc291cmNlID0gbW5fdXBfdG9wX3Rlcm1zX2FsbCRyZXN1bHQkc291cmNlW21uX3VwX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fc2l6ZSA8IDUwMCAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW5fdXBfdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9zaXplID4gMV0KKQoKa25pdHI6OmthYmxlKGhlYWQobW5fdXBfdG9wX3Rlcm1zLCAxMCksIGZvcm1hdCA9ICJodG1sIikKYGBgCkZvciBjb250ZXh0LCBsZXQncyBleGFtaW5lIHRoZSB0b3AgdGVybSBmcm9tIGVhY2ggZGF0YSBzb3VyY2UuCgpgYGB7ciBtbl91cF90b3BfdGVybV9wZXJfY2F0ZWdvcnksIG1lc3NhZ2U9RkFMU0V9CmtuaXRyOjprYWJsZShyYmluZChtbl91cF90b3BfdGVybXNbbW5fdXBfdG9wX3Rlcm1zJHNvdXJjZSA9PSAiR086QlAiLF1bMSxdLAogICAgICAgICAgICAgICAgICAgbW5fdXBfdG9wX3Rlcm1zW21uX3VwX3RvcF90ZXJtcyRzb3VyY2UgPT0gIlJFQUMiLF1bMSxdLAogICAgICAgICAgICAgICAgICAgbW5fdXBfdG9wX3Rlcm1zW21uX3VwX3RvcF90ZXJtcyRzb3VyY2UgPT0gIldQIixdWzEsXSksCiAgICAgICAgICAgICBmb3JtYXQgPSAiaHRtbCIpCmBgYApXZSBjYW4gdmlzdWFsaXplIHRoZSBkaXN0cmlidXRpb24gb2YgdG9wIHRlcm1zIGZyb20gZWFjaCBkYXRhIHNvdXJjZSB1c2luZyBhbiBNYW5oYXR0YW4gcGxvdC4KCmBgYHtyIG1uX3VwX2Rpc3RfcGxvdCwgZmlnLmNhcD0iRmlndXJlIDExLiBNYW5oYXR0YW4gcGxvdCBkaXNwbGF5aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHRvcCB0ZXJtcyBmcm9tIGVhY2ggZGF0YSBzb3VyY2UgZm9yIHVwLXJlZ3VsYXRlZCBnZW5lcyBpbiBtZXRhc3Rhc2VzIHZzLiBub3JtYWwgY29tcGFyaXNvbi4gVGhlcmUgYXJlIG1hbnkgdGVybXMgZXhjZWVkaW5nIDE2IGFkanVzdGVkIHAgdmFsbHVlLCBpbmRpY2F0aW5nIHZlcnkgc3Ryb25nIGVucmljaG1lbnQgc2lnbmFsLiJ9Cmdwcm9maWxlcjI6Omdvc3RwbG90KG1uX3VwX3RvcF90ZXJtc19hbGwpICU+JSBwbG90bHk6OmxheW91dCh0aXRsZSA9ICJNYW5oYXR0YW4gcGxvdCBmb3IgdXByZWd1bGF0ZWQgZ2VuZXMgKE1ldGFzdGFzZXMgdnMuIE5vcm1hbCkiLCBmb250ID0gbGlzdChzaXplID0gMTApKQpgYGAKCk51bWJlciBvZiB0ZXJtczoKYGBge3IgbW5fY291bnRfdXBfdG9wX3Rlcm1zLCBtZXNzYWdlPUZBTFNFfQpsZW5ndGgobW5fdXBfdG9wX3Rlcm1zJHRlcm1fbmFtZSkKYGBgCgojIyMgRG93bnJlZ3VsYXRlZCBHZW5lcwoKV2UgZG8gdGhlIHNhbWUgZm9yIHRoZSBkb3ducmVndWFsdGVkIGdlbmVzLgoKYGBge3IgbW5fZ3Byb2ZpbGVyX2Rvd24sIG1lc3NhZ2U9RkFMU0V9Cm1uX2Rvd25fdG9wX3Rlcm1zX2FsbCA8LSBncHJvZmlsZXIyOjpnb3N0KHF1ZXJ5ID0gcm93bmFtZXMoZG93bnJlZ3VsYXRlZF9tbiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JnYW5pc20gPSAiaHNhcGllbnMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4Y2x1ZGVfaWVhID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcnJlY3Rpb25fbWV0aG9kID0gImZkciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2VzID0gYygiR086QlAiLCAiUkVBQyIsICJXUCIpKQoKbW5fZG93bl90b3BfdGVybXMgPC0gZGF0YS5mcmFtZSgKICB0ZXJtX25hbWUgPSBtbl9kb3duX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fbmFtZVttbl9kb3duX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fc2l6ZSA8IDUwMCAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtbl9kb3duX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fc2l6ZSA+IDFdLAogIHRlcm1faWQgPSBtbl9kb3duX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1faWRbbW5fZG93bl90b3BfdGVybXNfYWxsJHJlc3VsdCR0ZXJtX3NpemUgPCA1MDAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtbl9kb3duX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fc2l6ZSA+IDFdLAogIHNvdXJjZSA9IG1uX2Rvd25fdG9wX3Rlcm1zX2FsbCRyZXN1bHQkc291cmNlW21uX2Rvd25fdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9zaXplIDwgNTAwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1uX2Rvd25fdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9zaXplID4gMV0KKQoKa25pdHI6OmthYmxlKGhlYWQobW5fZG93bl90b3BfdGVybXMsIDEwKSwgZm9ybWF0ID0gImh0bWwiKQpgYGAKCmBgYHtyIG1uX2Rvd25fdG9wX3Rlcm1fcGVyX2NhdGVnb3J5LCBtZXNzYWdlPUZBTFNFfQprbml0cjo6a2FibGUocmJpbmQobW5fZG93bl90b3BfdGVybXNbbW5fZG93bl90b3BfdGVybXMkc291cmNlID09ICJHTzpCUCIsXVsxLF0sCiAgICAgICAgICAgICAgICAgICBtbl9kb3duX3RvcF90ZXJtc1ttbl9kb3duX3RvcF90ZXJtcyRzb3VyY2UgPT0gIlJFQUMiLF1bMSxdLAogICAgICAgICAgICAgICAgICAgbW5fZG93bl90b3BfdGVybXNbbW5fZG93bl90b3BfdGVybXMkc291cmNlID09ICJXUCIsXVsxLF0pLAogICAgICAgICAgICAgZm9ybWF0ID0gImh0bWwiKQpgYGAKUGxvdCB0aGUgTWFuaGF0dGFuIHBsb3Qgc2hvd2luZyBkaXN0cmlidXRpb24gb2YgdGVybXMgZnJvbSBlYWNoIGRhdGEgc291cmNlIHVzaW5nIGxpc3Qgb2YgZG93bnJlZ3VsYXRlZCBnZW5lcy4KCmBgYHtyIG1uX2Rvd25fZGlzdF9wbG90LCBmaWcuY2FwPSJGaWd1cmUgMTIuIE1hbmhhdHRhbiBwbG90IGRpc3BsYXlpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgdG9wIHRlcm1zIGZyb20gZWFjaCBkYXRhIHNvdXJjZSBmb3IgZG93bi1yZWd1bGF0ZWQgZ2VuZXMgaW4gbWV0YXN0YXNlcyB2cy4gbm9ybWFsIGNvbXBhcmlzb24uIFRoZXJlIGFyZSBsZXNzIHRlcm1zIGludm9sdmVkIGZvciBkb3duLXJlZ3VsYXRlZCBnZW5lcyBjb21wYXJlZCB0byB0aGUgdXAtcmVndWxhdGVkIGdlbmVzLiJ9Cmdwcm9maWxlcjI6Omdvc3RwbG90KG1uX2Rvd25fdG9wX3Rlcm1zX2FsbCkgJT4lIAogIHBsb3RseTo6bGF5b3V0KHRpdGxlID0gIk1hbmhhdHRhbiBwbG90IGZvciBkb3ducmVndWxhdGVkIGdlbmVzIChNZXRhc3Rhc2VzIHZzLiBOb3JtYWwpIiwgZm9udCA9IGxpc3Qoc2l6ZSA9IDEwKSkKYGBgCgpOdW1iZXIgb2YgdGVybXMgcmV0dXJuZWQ6CmBgYHtyIG1uX2NvdW50X2Rvd25fdG9wX3Rlcm1zLCBtZXNzYWdlPUZBTFNFfQpsZW5ndGgobW5fZG93bl90b3BfdGVybXMkdGVybV9uYW1lKQpgYGAKCiMjIyBBbGwgRGlmZmVyZW50aWFsbHkgRXhwcmVzc2VkIEdlbmVzCgpGaW5hbGx5LCBmb3IgYWxsIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcy4KCmBgYHtyIG1uX2dwcm9maWxlcl9vdmVyYWxsLCBtZXNzYWdlPUZBTFNFfQptbl90b3BfdGVybXNfYWxsIDwtIGdwcm9maWxlcjI6Omdvc3QocXVlcnkgPSByb3duYW1lcyhkb3ducmVndWxhdGVkX21uKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmdhbmlzbSA9ICJoc2FwaWVucyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjbHVkZV9pZWEgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ycmVjdGlvbl9tZXRob2QgPSAiZmRyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZXMgPSBjKCJHTzpCUCIsICJSRUFDIiwgIldQIikpCgptbl90b3BfdGVybXMgPC0gZGF0YS5mcmFtZSgKICB0ZXJtX25hbWUgPSBtbl90b3BfdGVybXNfYWxsJHJlc3VsdCR0ZXJtX25hbWVbbW5fdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9zaXplIDwgNTAwICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtbl90b3BfdGVybXNfYWxsJHJlc3VsdCR0ZXJtX3NpemUgPiAxXSwKICB0ZXJtX2lkID0gbW5fdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9pZFttbl90b3BfdGVybXNfYWxsJHJlc3VsdCR0ZXJtX3NpemUgPCA1MDAgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW5fdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9zaXplID4gMV0sCiAgc291cmNlID0gbW5fdG9wX3Rlcm1zX2FsbCRyZXN1bHQkc291cmNlW21uX3RvcF90ZXJtc19hbGwkcmVzdWx0JHRlcm1fc2l6ZSA8IDUwMCAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW5fdG9wX3Rlcm1zX2FsbCRyZXN1bHQkdGVybV9zaXplID4gMV0KKQoKa25pdHI6OmthYmxlKGhlYWQobW5fdG9wX3Rlcm1zLCAxMCksIGZvcm1hdCA9ICJodG1sIikKYGBgCgpUb3AgdGVybXMgZnJvbSBlYWNoIGRhdGEgc291cmNlIGZvciBhbGwgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIChNZXRhc3Rhc2VzIHZzLiBOb3JtYWwpCmBgYHtyIG1uX3RvcF90ZXJtX3Blcl9jYXRlZ29yeSwgbWVzc2FnZT1GQUxTRX0Ka25pdHI6OmthYmxlKHJiaW5kKG1uX3RvcF90ZXJtc1ttbl90b3BfdGVybXMkc291cmNlID09ICJHTzpCUCIsXVsxLF0sCiAgICAgICAgICAgICAgICAgICBtbl90b3BfdGVybXNbbW5fdG9wX3Rlcm1zJHNvdXJjZSA9PSAiUkVBQyIsXVsxLF0sCiAgICAgICAgICAgICAgICAgICBtbl90b3BfdGVybXNbbW5fdG9wX3Rlcm1zJHNvdXJjZSA9PSAiV1AiLF1bMSxdKSwKICAgICAgICAgICAgIGZvcm1hdCA9ICJodG1sIikKYGBgCgpBbmQgYWdhaW4sIHdlIHBsb3QgdGhlIE1hbmhhdHRhbiBwbG90IHRvIHZpc3VhbGl6ZSB0aGUgdGVybXMgZW5yaWNobWVudDoKYGBge3IgbW5fYWxsX2Rpc3RfcGxvdCwgZmlnLmNhcD0iRmlndXJlIDEyLiBNYW5oYXR0YW4gcGxvdCBkaXNwbGF5aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHRvcCB0ZXJtcyBmcm9tIGVhY2ggZGF0YSBzb3VyY2UgZm9yIGFsbCBnZW5lcyBpbiBtZXRhc3Rhc2VzIHZzLiBub3JtYWwgdGlzc3VlIGNvbXBhcmlzb24uIFRoZXJlIGFyZSBsZXNzIHRlcm1zIGludm9sdmVkIGZvciB0aGlzIGNvbXBhcmlzb24sIGNvbXBhcmluZyB0byB0aGUgdHVtb3IgdnMuIG5vcm1hbCBncm91cC4ifQpncHJvZmlsZXIyOjpnb3N0cGxvdChtbl90b3BfdGVybXNfYWxsKSAlPiUgCiAgcGxvdGx5OjpsYXlvdXQodGl0bGUgPSAiTWFuaGF0dGFuIHBsb3QgZm9yIEFsbCBERSBnZW5lcyAKICAgICAgICAgICAgICAgICAoTWV0YXN0YXNlcyB2cy4gTm9ybWFsKSIsIGZvbnQgPSBsaXN0KHNpemUgPSAxMCkpCmBgYAoKTnVtYmVyIG9mIHRlcm1zOgpgYGB7ciBtbl9jb3VudF90b3BfdGVybXMsIG1lc3NhZ2U9RkFMU0V9Cmxlbmd0aChtbl90b3BfdGVybXMkdGVybV9uYW1lKQpgYGAKCgojIyBUaHJlc2hvbGRlZCBPdmVyLXJlcHJlc2VudGF0aW9uIGFuYWx5c2lzIERpc2N1c3Npb24KCiMjIyAxLiBXaGljaCBtZXRob2QgZGlkIHlvdSBjaG9vc2UgYW5kIHdoeT8KCkkgY2hvc2UgZzpQcm9maWxlciBiZWNhdXNlIGl0IHdhcyBkaXNjdXNzZWQgaW4gbGVjdHVyZXMsIGFuZCBwcmV2aW91cyBKb3VybmFsIEVudHJ5IGFzc2lnbm1lbnQgaGFzIGludHJvZHVjZWQgdGhlIGc6UHJvZmlsZXIgdG8gdXMgd2l0aCBpdHMgdXNhZ2UuIEl0IHByb3ZpZGVzIHNldmVyYWwgYW5hbHlzaXMgbWV0aG9kcyBhbmQgdmlzdWFsaXphdGlvbnMgZm9yIGdlbm9taWMgZGF0YSwgd2hpY2ggbWVldHMgb3VyIG5lZWQuIE1vcmVvdmVyLCBJIGhhZCBwcmV2aW91cyBleHBlcmllbmNlIHVzaW5nIGl0cyB3ZWItaW50ZXJmYWNlLCBhbmQgYWZ0ZXIgbGVhcm5pbmcgdGhhdCBpdCBhbHNvIGhhcyBSIHBhY2thZ2UgdXRpbGl0eSwgdGhpcyBpcyBhIGdvb2QgY2hhbmNlIHRvIHRyeSBpdCBvdXQuIAoKIyMjIDIuIFdoYXQgYW5ub3RhdGlvbiBkYXRhIGRpZCB5b3UgdXNlIGFuZCB3aHk/IFdoYXQgdmVyc2lvbiBvZiB0aGUgYW5ub3RhdGlvbiBhcmUgeW91IHVzaW5nPwpJIGNob29zZSBHTzpCUCwgUmVhY3RvbWUsIGFuZCBXaWtpUGF0aHdheXMgZm9yIGFubm90YXRpb24gYmVjYXVzZSB0aGV5IHdlcmUgcHJldmlvdXNseSBtZW50aW9uZWQgaW4gdGhlIEpvdXJuYWwgQXNzaWdubWVudCwgd2hpY2ggd2VyZSBhbHNvIHVzZWQgb24gaHVtYW4gZ2VuZXMsIGFuZCB0aGVzZSB0aHJlZSBhcmUgdmVyeSBjb21wcmVoZW5zaXZlIGRhdGFzZXRzIGZvciBodW1hbiBwYXRod2F5cy4gVGhlIHZlcnNpb24gSSBhbSB1c2luZyBpcyBhcyBmb2xsb3dzOgotIEdPOkJQIHJlbGVhc2VzLzIwMjItMTItMDQKLSBSRUFDIHJlbGVhc2VzLzIwMjItMTItMjgKLSBXUCByZWxlYXNlcy8yMDIyMTIxMAoKIyMjIDMuIEhvdyBtYW55IGdlbmVzZXRzIHdlcmUgcmV0dXJuZWQgd2l0aCB3aGF0IHRocmVzaG9sZHM/CgpGb3IgYWxsIHRocmVlIGFuYWx5c2lzICh1c2luZyB1cHJlZ3VsYXRlZCwgZG93bnJlZ3VsYXRlZCwgYWxsIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCkgZm9yIGJvdGggdHVtb3IgdnMuIG5vcm1hbCB0aXNzdWUgYW5kIG1ldGFzdGFzZXMgdnMuIG5vcm1hbCB0aXNzdWUsIHdlIHVzZWQgYSB0aHJlc2hvbGQgb2YgYWRqdXN0ZWQgcCB2YWx1ZSBvZiAwLjAxLCBhbmQgbGltaXQgdGVybSBzaXplIGJldHdlZW4gMSBhbmQgNTAwLiBXZSBzZXQgdGhlIHVwcGVyIGJvdW5kIHRvIDUwMCBiZWNhdXNlIHdlIGRvIG5vdCB3YW50IHRvIGluY2x1ZGUgb3Zlcmx5IGJyb2FkIGFuZCBnZW5lcmljIHRlcm1zIHRoYXQgd2lsbCBub3QgZ2l2ZSB1cyBtZWFuaW5nZnVsIGluc2lnaHRzIGludG8gdGhlIHJvbGVzIG9mIHRoZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMuIFRoZSBQIHZhbHVlIHRocmVzaG9sZCBpcyBzZXQgdG8gMC4wMS4KClR1bW9yIHZzLiBOb3JtYWw6IDxicj4KVXByZWd1bGF0ZWQgZ2VuZXMgcmV0dXJuZWQgNDkwIGdlbmUgc2V0czsgCkRvd25yZWd1bGF0ZWQgZ2VuZXMgcmV0dXJuZWQgMTU0IGdlbmVzIGV0czsgCkFsbCBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgcmV0dXJuZWQgMTE1MSBnZW5lIHNldHMuCgpNZXRhc3Rhc2VzIHZzLiBOb3JtYWw6IDxicj4KVXByZWd1bGF0ZWQgZ2VuZXMgcmV0dXJuZWQgMTE4MCBnZW5lIHNldHM7IApEb3ducmVndWxhdGVkIGdlbmVzIHJldHVybmVkIDE2MiBnZW5lIHNldHM7IApBbGwgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIHJldHVybmVkIDE2MiBnZW5lIHNldHMuCgojIyMgNC4gUnVuIHRoZSBhbmFseXNpcyB1c2luZyB0aGUgdXAtcmVndWxhdGVkIHNldCBvZiBnZW5lcywgYW5kIHRoZSBkb3duLXJlZ3VsYXRlZCBzZXQgb2YgZ2VuZXMgc2VwYXJhdGVseS4gSG93IGRvIHRoZXNlIHJlc3VsdHMgY29tcGFyZSB0byB1c2luZyB0aGUgd2hvbGUgbGlzdCAoaS5lIGFsbCBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMgdG9nZXRoZXIgdnMuIHRoZSB1cC1yZWd1bGF0ZWQgYW5kIGRvd24gcmVndWxhdGVkIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBzZXBhcmF0ZWx5KT8KClR1bW9yIHZzLiBOb3JtYWw6IDxicj4KVGFraW5nIGFsbCBERSBnZW5lcyB0b2dldGhlciByZXR1cm5lZCBtb3JlIGdlbmUgc2V0cyB0aGFuIHRoZSByZXN1bHRzIGZvciB1cHJlZ3VsYXRlZCBhbmQgZG93bnJlZ3VsYXRlZCBzZXBhcmF0ZWx5LCBhbmQgdGhlIHJlc3VsdHMgZm9yIHVwcmVndWxhdGVkIGdlbmVzIGFyZSBhYm91dCB0aHJlZSB0aW1lcyBtb3JlIHRoYW4gdGhlIGRvd25yZWd1bGF0ZWQgZ2VuZXMuIFRoaXMgc3VnZ2VzdHMgdGhhdCB0aGUgdXByZWd1bGF0ZWQgZ2VuZXMgbWF5IGJlIG1vcmUgc3Ryb25nbHkgYXNzb2NpYXRlZCB3aXRoIHNwZWNpZmljIGJpb2xvZ2ljYWwgcHJvY2Vzc2VzIG9yIHBhdGh3YXlzIHRoYW4gdGhlIGRvd25yZWd1bGF0ZWQgZ2VuZXMuIFNpbWlsYXJseSwgdGhlIGZhY3QgdGhhdCB0aGUgY29tYmluZWQgc2V0IG9mIERFIGdlbmVzIHJldHVybmVkIG1vcmUgZ2VuZSBzZXRzIHRoYW4gZWl0aGVyIHRoZSB1cHJlZ3VsYXRlZCBvciBkb3ducmVndWxhdGVkIGdlbmVzIGFsb25lIHN1Z2dlc3RzIHRoYXQgdGhlcmUgbWF5IGJlIHNvbWUgc2hhcmVkIGJpb2xvZ2ljYWwgcHJvY2Vzc2VzIG9yIHBhdGh3YXlzIHRoYXQgYXJlIGFmZmVjdGVkIGJ5IGJvdGggdXByZWd1bGF0ZWQgYW5kIGRvd25yZWd1bGF0ZWQgZ2VuZXMuCgpNZXRhc3Rhc2VzIHZzLiBOb3JtYWw6IDxicj4KVXByZWd1bGF0ZWQgZ2VuZXMgcmV0dXJuZWQgYXJvdW5kIDEwIHRpbWVzIG1vcmUgdGVybXMgdGhhbiB0aGUgcmVzdWx0IGZvciBhbGwgREUgZ2VuZXMgYXMgYSB3aG9sZS4gVGhpcyBpbmRpY2F0ZXMgdGhhdCB0aGUgdXByZWd1bGF0ZWQgZ2VuZXMgYXJlIGVucmljaGVkIGZvciBjZXJ0YWluIGJpb2xvZ2ljYWwgZnVuY3Rpb25zIG9yIHBhdGh3YXlzIG1vcmUgc3Ryb25nbHkgdGhhbiB0aGUgb3ZlcmFsbCBzZXQgb2YgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzLgoKCiMgSW50ZXJwcmV0YXRpb24KCiMjIyAxLiBEbyB0aGUgb3Zlci1yZXByZXNlbnRhdGlvbiByZXN1bHRzIHN1cHBvcnQgY29uY2x1c2lvbnMgb3IgbWVjaGFuaXNtIGRpc2N1c3NlZCBpbiB0aGUgb3JpZ2luYWwgcGFwZXI/Ck5vdCB0b28gbXVjaCwgdGhlIG92ZXItcmVwcmVzZW50YXRpb24gcmVzdWx0cyBkb2Vzbid0IHN0cm9uZ2x5IHN1cHBvcnQgdGhlIGNvbmNsdXNpb25zIGFuZCBtZWNoYW5pc20gZGlzY3Vzc2VkIGluIHRoZSBvcmlnaW5hbCBwYXBlciwgcHJvYmFibHkgZHVlIHRvIHRoZSBhbm5vdGF0aW9uIHNvdXJjZXMgdGhhdCBJIGNob29zZSB0aGF0IHllbGRzIGRpZmZlcmVudCByZXN1bHRzLiBIb3dldmVyLCB0ZXJtcyBzdWNoIGFzIHJlZ3VsYXRpb24gb2YgbWl0b3RpYyBjZWxsIGN5Y2xlIHNob3dlZCB1cCB3aXRoaW4gdGhlIGFuYWx5c2lzIHJlc3VsdCBmb3IgdXAtcmVndWxhdGVkIGdlbmUgc2V0cyBmb3IgdHVtb3IgdGlzc3VlcyBhbmQgbWV0YXN0YXNlcyB0aXNzdWVzLiBJbiB0aGUgb3JpZ2luYWwgcGFwZXIsIHRoZSBhdXRob3JzIHByZWRpY3RlZCB0aGF0IHRoZSB0dW1vcnMgd291bGQgaGF2ZSBURnMgdGhhdCBpbnRlcmFjdCB3aXRoIHRoZSBNQVBLIHBhdGh3YXkgYW5kIHJlZ3VsYXRlIGdlbmUgZXhwcmVzc2lvbiBpbiBhIHdheSB0aGF0IGlzIHJlbGV2YW50IHRvIHRoZSBkZXZlbG9wbWVudCBhbmQgcHJvZ3Jlc3Npb24gb2YgY2FuY2VyLCBhbmQgaW5kZWVkIHRoZXkgZm91bmQgdGhhdCBURnMgaW4gdGhlIE1BUEsgcGF0aHdheSBhcmUgYWN0aXZlbHkgYm91bmQgc2lnbmlmaWNhbnRseSBtb3JlIGluIHR1bW9yIGFuZCBtZXRhc3Rhc2VzIHRoYW4gaW4gbm9ybWFsIHRpc3N1ZS4gVHJhbnNjcmlwdGlvbiBmYWN0b3JzIGFyZSB3aWRlbHkga25vdyB0byBwbGF5IGEgcm9sZSBpbiByZWd1bGF0aW5nIGdlbmUgZXhwcmVzaXNvbiwgd2hpY2ggd291bGQgYWxzbyBhZmZlY3QgbWl0b3RpYyBjZWxsIGN5Y2xlLCBpbmRpY2F0aW5nIHRoYXQgb3VyIHJlc3VsdHMgc3VwcG9ydCB0aGUgY29uY2x1c2lvbnMgZGlzY3Vzc2VkIGluIHRoZSBvcmlnaW5hbCBwYXBlciBpbiBzb21lIHdheS4KCiMjIyAyLiBDYW4geW91IGZpbmQgZXZpZGVuY2UsIGkuZS4gcHVibGljYXRpb25zLCB0byBzdXBwb3J0IHNvbWUgb2YgdGhlIHJlc3VsdHMgdGhhdCB5b3Ugc2VlLiBIb3cgZG9lcyB0aGlzIGV2aWRlbmNlIHN1cHBvcnQgeW91ciByZXN1bHRzLiAKClRoZXJlIGFyZSBwdWJsaWNhdGlvbnMgZGVzY3JpYmluZyBob3cgdHJhbnNjcmlwdGlvbiBmYWN0b3JzIHJlZ3VsYXRlcyBtaXRvdGljIGNlbGwgY3ljbGUuIEluIHRoZSByZXZpZXcgcGFwZXIgIkNvb3JkaW5hdGluZyBnZW5lIGV4cHJlc3Npb24gZHVyaW5nIHRoZSBjZWxsIGN5Y2xlIiBieSBNYXJ0aW4uRiBldC4gYWwsIHRoZXkgZGlzY3Vzc2VkIHRoZSBjb250cm9sIG1lY2hhbmlzbXMgZm9yIG1pdG90aWMgY2VsbCBjeWNsZXMgaW4gbWFtbWFscywgd2hpY2ggaW5jbHVkZSBhY3RpdmF0aW5nIGdlbmVzIHdpdGggcGVhayBleHByZXNzaW9uIGluIEcxL1MgYnkgRTJGIHRyYW5zY3JpcHRpb24gZmFjdG9ycyAoVEZzKSwgd2hpY2ggaXMgcmVxdWlyZWQgZm9yIEROQSBzeW50aGVzaXMuIChARklTQ0hFUjIwMjIxMDA5KS4gCgoKIyBSZWZlcmVuY2VzCgoKCg==